grit sync for mobile
Types flow from Go structs.
The whole point of the mobile kit is type-safety from Go struct to React Native screen. grit sync is the command that makes that real. This lesson covers what it does and how mobile consumes the output.
The sync
$grit sync
Reads every model in apps/api/internal/models/, writes a matching TypeScript type in packages/shared/src/types/. Same Concepts course coverage, same command — works identically in the mobile kit.
What mobile gets
export interface User {id: stringemail: stringname: stringrole: 'user' | 'staff' | 'admin'created_at: stringupdated_at: string}
The mobile app imports this directly:
import { useQuery } from '@tanstack/react-query'import type { User } from '@grit/shared/types/user'import { api } from '@/lib/api'export function useUsers() {return useQuery<User[]>({queryKey: ['users'],queryFn: () => api.get('/api/users').then((r) => r.data.data),})}
TypeScript autocompletes user.role with the three valid string literals. If the Go side adds a new role,grit sync picks it up and TS catches every place that doesn't handle it.
Zod schemas too
grit sync also writes Zod schemas. Use them to validate form input before it leaves the device:
import { CreateUserSchema } from '@grit/shared/schemas/user'const result = CreateUserSchema.safeParse(formInput)if (!result.success) {// result.error.flatten() gives per-field errors for the form}
Same Zod schema validates on mobile, web, and as a sanity check on the API before GORM writes.
When to re-run sync
- After
grit generate resource ...on the API - After manually editing a Go struct in
internal/models/ - After pulling main if a teammate changed models
Wire it into your dev script:
{"scripts": {"dev": "grit sync && turbo dev"}}
Now every pnpm dev starts fresh with synced types.
packages/shared/src/types/ to .gitignore? Don't. Even though it's generated, committing it means CI doesn't need a Go install to build the mobile app. Lock-step Go and TS changes via PR.What sync doesn't handle
- Computed / derived fields. If your handler decorates the response with extra fields, those aren't in the Go struct — TS won't know. Add them manually to a type extension.
- Custom JSON marshalling. If you implement
MarshalJSONon a Go type to reshape it, sync sees the struct, not the actual wire format.
Quick check
Try it
Trigger the sync flow end-to-end:
- Add a field to your Go User model:
Bio string `json:"bio"` - Run
grit migrate - In
apps/mobile/app/index.tsx, try to accessuser.bio— TypeScript yells - Run
grit sync - The error is gone — paste before/after in
notes.md
What's next
Types are aligned. Last lesson of the chapter — wrap the API client in a thin TypeScript layer that mobile screens consume via React Query.
Spot a typo? Have an idea?
Help us improve this lesson. One click opens a GitHub issue with the lesson URL pre-filled — suggest clearer wording, report a bug, or request more depth. The course keeps improving thanks to learners like you.
Suggest an improvement on GitHub