search
Vue star Featured

Fix: defineProps is not defined in Vue.js Error

Learn how to fix the 'defineProps is not defined' error in Vue.js applications. This comprehensive guide covers Composition API, TypeScript, and best practices.

person By Gautam Sharma
calendar_today January 2, 2026
schedule 11 min read
Vue.js defineProps Composition API Error Frontend Development TypeScript

The ‘defineProps is not defined’ error is a common Vue 3 Composition API issue that occurs when trying to use defineProps without proper setup or in the wrong context. This error typically happens when using the Composition API with <script setup> or when there are issues with the build configuration.

This comprehensive guide explains what causes this error, why it happens, and provides multiple solutions to fix it in your Vue.js projects with clean code examples and directory structure.


What is the defineProps Error?

The “defineProps is not defined” error occurs when:

  • Using defineProps outside of <script setup> context
  • Not using Vue 3 with Composition API
  • Build tools aren’t properly configured for macro functions
  • TypeScript configuration issues
  • Using defineProps in Options API components
  • Importing defineProps explicitly (which is not needed)

Common Error Messages:

  • defineProps is not defined
  • ReferenceError: defineProps is not defined
  • Cannot access 'defineProps' before initialization
  • defineProps is not a function
  • TypeError: defineProps is not defined

Understanding the Problem

defineProps is a compile-time macro function in Vue 3’s Composition API that’s only available within <script setup> blocks. It’s used to define props in a more concise way compared to the Options API. The error occurs when Vue’s compiler doesn’t recognize defineProps as a built-in macro function.

Typical Vue.js Project Structure:

my-vue-app/
├── package.json
├── vite.config.js
├── src/
│   ├── main.js
│   ├── App.vue
│   ├── components/
│   │   ├── ChildComponent.vue
│   │   └── ParentComponent.vue
│   ├── composables/
│   │   └── useProps.js
│   ├── assets/
│   └── styles/
│       └── main.css
└── public/

Solution 1: Use defineProps in Script Setup

The most common solution is to ensure defineProps is used within <script setup>.

❌ Without Script Setup:

<template>
  <div>
    <h2>{{ title }}</h2>
    <p>{{ message }}</p>
  </div>
</template>

<script>
// ❌ defineProps is not available here
const props = defineProps({
  title: String,
  message: {
    type: String,
    default: 'Default message'
  }
})
</script>

✅ With Script Setup:

ChildComponent.vue:

<template>
  <div>
    <h2>{{ title }}</h2>
    <p>{{ message }}</p>
  </div>
</template>

<script setup>
// ✅ defineProps is available in <script setup>
const props = defineProps({
  title: {
    type: String,
    required: true
  },
  message: {
    type: String,
    default: 'Default message'
  }
})
</script>

Solution 2: Use TypeScript with defineProps

Properly configure TypeScript with defineProps for type safety.

❌ Without TypeScript Support:

<script setup>
// ❌ No type safety
const props = defineProps({
  title: String,
  count: Number
})
</script>

✅ With TypeScript Support:

<script setup lang="ts">
// ✅ TypeScript interface for props
interface Props {
  title: string
  count?: number
  isActive?: boolean
}

// ✅ Type-safe props definition
const props = withDefaults(defineProps<Props>(), {
  count: 0,
  isActive: false
})
</script>

Solution 3: Check Vue Version Compatibility

Ensure you’re using Vue 3 with Composition API support.

❌ Vue 2 Usage:

// ❌ defineProps is not available in Vue 2
import Vue from 'vue'

export default {
  // ❌ This won't work in Vue 2
  setup() {
    const props = defineProps(['title', 'message'])
  }
}

✅ Vue 3 Usage:

<template>
  <div>
    <h2>{{ title }}</h2>
    <p>{{ message }}</p>
  </div>
</template>

<script setup>
// ✅ defineProps is available in Vue 3
const props = defineProps({
  title: String,
  message: String
})
</script>

Solution 4: Configure Build Tools Properly

Ensure your build tools are properly configured for Vue 3 macro functions.

❌ Without Proper Build Configuration:

// vite.config.js - ❌ Missing Vue plugin
import { defineConfig } from 'vite'

export default defineConfig({
  // ❌ Missing @vitejs/plugin-vue
})

✅ With Proper Build Configuration:

// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [
    vue({
      // ✅ Enable reactivity transform if needed
      reactivityTransform: false
    })
  ]
})

package.json:

{
  "name": "my-vue-app",
  "version": "1.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build"
  },
  "dependencies": {
    "vue": "^3.0.0" // ✅ Vue 3 dependency
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^4.0.0", // ✅ Vue plugin for Vite
    "vite": "^4.0.0"
  }
}

Solution 5: Use Options API Alternative

If you can’t use Composition API, use the traditional Options API.

❌ With defineProps in Options API:

<template>
  <div>
    <h2>{{ title }}</h2>
  </div>
</template>

<script>
export default {
  // ❌ defineProps doesn't work in Options API
  props: defineProps(['title']) // ❌ Error
}
</script>

✅ With Options API:

<template>
  <div>
    <h2>{{ title }}</h2>
  </div>
</template>

<script>
export default {
  name: 'ChildComponent',
  props: {
    title: {
      type: String,
      required: true
    },
    message: {
      type: String,
      default: 'Default message'
    }
  }
}
</script>

Solution 6: Handle Complex Prop Types

Use proper syntax for complex prop definitions.

ComplexProps.vue:

<script setup lang="ts">
// ✅ Define complex prop types
interface User {
  id: number
  name: string
  email: string
}

interface Props {
  title: string
  user: User
  items: string[]
  callback?: () => void
  config?: {
    theme: 'light' | 'dark'
    size: 'small' | 'medium' | 'large'
  }
}

const props = withDefaults(defineProps<Props>(), {
  items: () => [],
  config: () => ({
    theme: 'light',
    size: 'medium'
  })
})
</script>

<template>
  <div>
    <h2>{{ title }}</h2>
    <p>User: {{ user.name }} ({{ user.email }})</p>
    <ul>
      <li v-for="item in items" :key="item">{{ item }}</li>
    </ul>
    <p>Theme: {{ config?.theme }}, Size: {{ config?.size }}</p>
  </div>
</template>

Solution 7: Use Runtime vs Compile-time Definitions

Choose between runtime and compile-time prop definitions based on your needs.

Runtime Definition (More Flexible):

<script setup>
// ✅ Runtime prop definition
const props = defineProps({
  title: {
    type: String,
    required: true,
    validator: (value: string) => value.length > 0
  },
  count: {
    type: Number,
    default: 0,
    validator: (value: number) => value >= 0
  }
})
</script>

Compile-time Definition (Better Type Safety):

<script setup lang="ts">
// ✅ Compile-time prop definition with TypeScript
interface Props {
  title: string
  count?: number
}

const props = withDefaults(defineProps<Props>(), {
  count: 0
})
</script>

Working Code Examples

Complete Component with defineProps:

<template>
  <div class="user-card">
    <h2>{{ title }}</h2>
    <div v-if="user" class="user-info">
      <h3>{{ user.name }}</h3>
      <p>{{ user.email }}</p>
      <p v-if="user.age" class="age">Age: {{ user.age }}</p>
    </div>
    <div v-else class="no-user">No user data available</div>
    
    <div class="stats">
      <p>Visits: {{ visits }}</p>
      <p>Active: {{ isActive ? 'Yes' : 'No' }}</p>
    </div>
    
    <div v-if="tags && tags.length" class="tags">
      <span 
        v-for="tag in tags" 
        :key="tag" 
        class="tag"
      >
        {{ tag }}
      </span>
    </div>
  </div>
</template>

<script setup lang="ts">
interface User {
  name: string
  email: string
  age?: number
}

interface Props {
  title: string
  user?: User
  visits?: number
  isActive?: boolean
  tags?: string[]
}

// ✅ Define props with defaults
const props = withDefaults(defineProps<Props>(), {
  visits: 0,
  isActive: false,
  tags: () => []
})
</script>

<style scoped>
.user-card {
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 20px;
  max-width: 400px;
  margin: 20px auto;
}

.user-info {
  margin: 15px 0;
}

.age {
  color: #666;
  font-style: italic;
}

.no-user {
  color: #999;
  font-style: italic;
}

.stats {
  margin: 15px 0;
}

.tags {
  margin-top: 15px;
}

.tag {
  display: inline-block;
  background-color: #e9ecef;
  color: #495057;
  padding: 4px 8px;
  border-radius: 12px;
  margin-right: 5px;
  font-size: 0.8em;
}
</style>

Parent Component Usage:

<template>
  <div class="parent">
    <h1>Parent Component</h1>
    
    <UserCard 
      title="User Profile"
      :user="userData"
      :visits="42"
      :is-active="true"
      :tags="['developer', 'vue', 'javascript']"
    />
    
    <UserCard 
      title="Guest Profile"
      :visits="0"
      :is-active="false"
    />
  </div>
</template>

<script setup lang="ts">
import UserCard from './UserCard.vue'

interface User {
  name: string
  email: string
  age?: number
}

const userData: User = {
  name: 'John Doe',
  email: 'john@example.com',
  age: 30
}
</script>

Best Practices for defineProps

1. Always Use Script Setup

// ✅ Always use <script setup> for defineProps
<script setup>
const props = defineProps(/* ... */)
</script>

2. Use TypeScript for Type Safety

// ✅ Use TypeScript interfaces for better type safety
interface Props {
  title: string
  count?: number
}

3. Provide Default Values

// ✅ Use withDefaults for optional props
const props = withDefaults(defineProps<Props>(), {
  count: 0
})

4. Validate Props When Needed

// ✅ Use runtime validation when needed
const props = defineProps({
  title: {
    type: String,
    required: true,
    validator: (value: string) => value.length > 0
  }
})

Debugging Steps

Step 1: Check Vue Version

# Verify Vue version is 3.x
npm list vue

Step 2: Check Build Configuration

# Verify build tools are configured for Vue 3
grep -r "vue" vite.config.js

Step 3: Verify Script Setup Usage

<!-- Ensure you're using <script setup> -->
<script setup>
// defineProps should be available here
</script>

Step 4: Check TypeScript Configuration

# If using TypeScript, verify tsconfig
npx vue-tsc --noEmit

Common Mistakes to Avoid

1. Using defineProps Outside Script Setup

<!-- ❌ Don't use defineProps outside of <script setup> -->
<script>
const props = defineProps(['title']) // ❌ Error
</script>

2. Importing defineProps Explicitly

<!-- ❌ Don't import defineProps -->
<script setup>
import { defineProps } from 'vue' // ❌ Not needed

const props = defineProps(['title'])
</script>

3. Using in Vue 2 Projects

// ❌ defineProps is not available in Vue 2
import Vue from 'vue2' // ❌ Wrong version

4. Not Using Vue Plugin

// ❌ Missing Vue plugin in build configuration
export default defineConfig({
  // ❌ Missing @vitejs/plugin-vue
})

Performance Considerations

1. Use Compile-time Definitions When Possible

// ✅ Compile-time definitions are more performant
interface Props {
  title: string
  count?: number
}

2. Avoid Complex Runtime Validation

// ❌ Avoid complex runtime validation in production
const props = defineProps({
  complexObject: {
    type: Object,
    validator: (value) => {
      // Complex validation can impact performance
      return validateComplexObject(value)
    }
  }
})

Security Considerations

1. Validate Input Data

// ✅ Always validate prop data
const props = defineProps({
  userInput: {
    type: String,
    validator: (value: string) => {
      // Validate to prevent XSS
      return typeof value === 'string' && value.length < 1000
    }
  }
})

2. Sanitize Prop Values

// ✅ Sanitize prop values before using
const sanitizedValue = sanitizeInput(props.userInput)

Testing Components with defineProps

1. Unit Test Prop Definitions

import { mount } from '@vue/test-utils'
import ChildComponent from '@/components/ChildComponent.vue'

describe('ChildComponent', () => {
  it('should accept props correctly', () => {
    const wrapper = mount(ChildComponent, {
      props: {
        title: 'Test Title',
        message: 'Test Message'
      }
    })
    
    expect(wrapper.props().title).toBe('Test Title')
    expect(wrapper.props().message).toBe('Test Message')
  })
  
  it('should use default values', () => {
    const wrapper = mount(ChildComponent, {
      props: {
        title: 'Test Title'
        // message should use default
      }
    })
    
    expect(wrapper.props().message).toBe('Default message')
  })
})

2. Test Type Validation

it('should validate prop types', () => {
  expect(() => {
    mount(ChildComponent, {
      props: {
        title: 123 // ❌ Should be string
      }
    })
  }).toThrow()
})

Alternative Solutions

1. Use Options API

<template>
  <div>{{ title }}</div>
</template>

<script>
export default {
  props: {
    title: String
  }
}
</script>

2. Use Composition API without defineProps

<script setup>
import { computed } from 'vue'

// ✅ Alternative approach using props parameter
export default {
  props: ['title', 'message']
}

// In setup function
const setup = (props) => {
  const processedTitle = computed(() => props.title.toUpperCase())
  return { processedTitle }
}
</script>

Migration Checklist

  • Verify Vue 3 is installed and configured
  • Check that components use <script setup>
  • Ensure build tools support Vue 3 macro functions
  • Test prop definitions work correctly
  • Verify TypeScript configuration (if using TypeScript)
  • Run unit tests to confirm functionality
  • Update documentation for team members

Conclusion

The ‘defineProps is not defined’ error is a common Vue 3 Composition API issue that occurs when trying to use defineProps in the wrong context or with incorrect configuration. By following the solutions provided in this guide—whether through proper <script setup> usage, correct build configuration, or TypeScript integration—you can ensure your Vue.js applications properly handle component props.

The key is to understand that defineProps is a compile-time macro function that’s only available within <script setup> blocks in Vue 3. With proper setup and configuration, your Vue.js applications will have clean, type-safe prop definitions that enhance code maintainability and developer experience.

Remember to always use Vue 3 with Composition API support, configure your build tools properly, and follow Vue’s best practices for prop definitions to create robust and maintainable components.

Gautam Sharma

About Gautam Sharma

Full-stack developer and tech blogger sharing coding tutorials and best practices

Related Articles

Vue

Fix: Cannot read property '$refs' of undefined in Vue.js

Learn how to fix the 'Cannot read property $refs of undefined' error in Vue.js applications. This comprehensive guide covers Vue instance access, lifecycle hooks, and best practices.

January 2, 2026
Vue

Fix: Property or method is not defined on the instance in Vue.js

Learn how to fix the 'Property or method is not defined on the instance' error in Vue.js applications. This comprehensive guide covers data properties, methods, and best practices.

January 2, 2026
Vue

How to Fix: Vue 3 emit is not defined error

Learn how to fix the 'emit is not defined' error in Vue 3 applications. This comprehensive guide covers Composition API, defineEmits, and best practices.

January 2, 2026