
Why plain TypeScript isn’t enough
If you hover over the result
from useQuery
in last week’s code, you’ll still see Ref<any>
. That means:
<li v-for="c in result?.countries2" :key="c.code">
…slips right past TypeScript.

It’s time to bring in GraphQL Code Generator which gives us:
- 100% typed operations, variables, and results
- Build-time schema validation (fail fast, ship safe)
Step 1: Install the right packages
Let’s start by installing the necessary dependencies:
npm i graphql
npm i -D typescript @graphql-codegen/cli
npm i -D @parcel/watcher
🚨
@parcel/watcher
is a dev dependency.
Step 2: Create a clean codegen.ts
Next, use the CLI to generate your config file:
npx graphql-code-generator init
When prompted, answer as follows:
? What type of application are you building? Application built with Vue
? Where is your schema?: (path or url) https://countries.trevorblades.com/graphql
? Where are your operations and fragments?: src/**/*.vue
? Where to write the output: src/gql/
? Do you want to generate an introspection file? No
? How to name the config file? codegen.ts
? What script in package.json should run the codegen? codegen
Fetching latest versions of selected plugins...
Your generated codegen.ts
should look like this:
import type { import CodegenConfig
CodegenConfig } from '@graphql-codegen/cli';
const const config: CodegenConfig
config: import CodegenConfig
CodegenConfig = {
overwrite: boolean
overwrite: true,
schema: string
schema: "https://countries.trevorblades.com/graphql",
documents: string
documents: "src/**/*.vue",
generates: {
"src/gql/": {
preset: string;
plugins: never[];
};
}
generates: {
"src/gql/": {
preset: string
preset: "client",
plugins: never[]
plugins: []
}
}
};
export default const config: CodegenConfig
config;
Step 3: Add dev scripts and watch mode
Update your package.json
scripts to streamline development:
{
"scripts": {
"codegen": "graphql-codegen --config codegen.ts",
"codegen:watch": "graphql-codegen --watch --config codegen.ts"
}
}
Step 4: Write your first typed query
Create a new file at src/queries/countries.graphql
:
query AllCountries {
countries {
code
name
emoji
}
}
Then, generate your types:
npm run codegen
The command writes all generated types to src/gql/
.
Update your CountryList.vue
component to use the generated types
<script setup lang="ts">
import { import useQuery
useQuery } from '@vue/apollo-composable'
import { import AllCountriesDocument
AllCountriesDocument } from '../gql/graphql'
import { const computed: {
<T>(getter: ComputedGetter<T>, debugOptions?: DebuggerOptions): ComputedRef<T>;
<T, S = T>(options: WritableComputedOptions<T, S>, debugOptions?: DebuggerOptions): WritableComputedRef<T, S>;
}
computed } from 'vue'
const { const result: any
result, const loading: any
loading, const error: any
error } = import useQuery
useQuery(import AllCountriesDocument
AllCountriesDocument)
const const countries: ComputedRef<any>
countries = computed<any>(getter: ComputedGetter<any>, debugOptions?: DebuggerOptions): ComputedRef<any> (+1 overload)
Takes a getter function and returns a readonly reactive ref object for the
returned value from the getter. It can also take an object with get and set
functions to create a writable ref object.computed(() => const result: any
result.value?.countries)
</script>

Inline queries with the generated graphql
tag
Alternatively, define the query directly in your component using the generated graphql
tag:
<script setup lang="ts">
import { import useQuery
useQuery } from '@vue/apollo-composable'
import { import graphql
graphql } from '../gql'
import { const computed: {
<T>(getter: ComputedGetter<T>, debugOptions?: DebuggerOptions): ComputedRef<T>;
<T, S = T>(options: WritableComputedOptions<T, S>, debugOptions?: DebuggerOptions): WritableComputedRef<T, S>;
}
computed } from 'vue'
const const COUNTRIES_QUERY: any
COUNTRIES_QUERY = import graphql
graphql(`
query AllCountries {
countries {
code
name
emoji
}
}
`)
const { const result: any
result, const loading: any
loading, const error: any
error } = import useQuery
useQuery(const COUNTRIES_QUERY: any
COUNTRIES_QUERY)
const const countries: ComputedRef<any>
countries = computed<any>(getter: ComputedGetter<any>, debugOptions?: DebuggerOptions): ComputedRef<any> (+1 overload)
Takes a getter function and returns a readonly reactive ref object for the
returned value from the getter. It can also take an object with get and set
functions to create a writable ref object.computed(() => const result: any
result.value?.countries)
</script>
Watch mode
With @parcel/watcher
installed, you can enable watch mode for a smoother development experience. If you frequently change your GraphQL schema while developing, simply run:
npm run codegen:watch
GraphQL Code Generator immediately throws an error when your local operations drift from the live schema. Remember, your GraphQL server needs to be running for this to work.
Bonus: Proper validation out of the box
A powerful benefit of this setup is automatic validation. If the Countries GraphQL API ever changes—say, it renames code
to code2
—you’ll get an error when generating types.
For example, if you query for code2
, you’ll see:
⚠ Generate outputs
❯ Generate to src/gql/
✔ Load GraphQL schemas
✔ Load GraphQL documents
✖ GraphQL Document Validation failed with 1 errors;
Error 0: Cannot query field "code2" on type "Country". Did you mean "code"?
Should you commit generated files?
A common question: should you commit the generated types to your repository?
Strategy | Pros | Cons |
---|---|---|
Commit them | Fast onboarding · Diff visibility | Noisy PRs · Merge conflicts |
Ignore them | Clean history · Zero conflicts | Extra npm run generate in CI/local |
Many teams choose to commit generated files, but enforce npm run generate -- --check
in CI to guard against stale artifacts.
Up next (Part 3)
- Fragments without repetition
Summary & Key Takeaways
In this part of the Vue 3 + GraphQL series, we:
- Set up GraphQL Code Generator v5 to create fully-typed queries and composables for Vue 3
- Learned how to configure
codegen.ts
for a remote schema and local.vue
operations - Automated type generation with dev scripts and watch mode for a smooth DX
- Used generated types and the
graphql
tag to eliminateany
and catch schema errors at build time - Discussed whether to commit generated files and best practices for CI
What you learned
- How to make your GraphQL queries type-safe and schema-validated in Vue 3
- How to avoid runtime errors and catch breaking API changes early
- How to streamline your workflow with codegen scripts and watch mode
- The tradeoffs of committing vs. ignoring generated files in your repo
Actionable reminders
- Always run
npm run generate
after changing queries or schema - Use the generated types in your components for full type safety
- Consider enforcing type checks in CI to prevent stale artifacts
Stay tuned for Part 3, where we’ll cover fragments and avoid repetition in your queries!
Source Code
Find the full demo for this series here: example
Note:
The code for this tutorial is on thepart-two
branch.
After cloning the repository, make sure to check out the correct branch:git clone https://github.com/alexanderop/vue-graphql-simple-example.git cd vue-graphql-simple-example git checkout part-two