If you are building a Medusa backend inside a monorepo and want your storefront to understand your Medusa data types, the first assumption is usually wrong:
Medusa does not give you a shared generated type contract in the same way that a system like Payload CMS does.
That distinction matters a lot.
In our monorepo, we have:
apps/medusa-backend for the Medusa app
apps/medusa-storefront for the Next.js storefront
packages/shared-types for types consumed across apps
The goal was simple:
let the storefront import Medusa-related types from @repo/shared-types
avoid importing from .medusa
avoid brittle copied generated files
keep the contract stable when the backend evolves
This guide explains the approach we ended up with, why it is the correct Medusa-style solution, and the gotchas we hit along the way.
The key difference: Payload CMS vs Medusa
Payload CMS and Medusa solve type generation differently.
Payload CMS
Payload can generate a shared TypeScript contract directly from your config. In our monorepo, Payload writes generated types to:
That lets the storefront import both Payload and Medusa types from one place.
How the storefront consumes them
Once the shared package is wired correctly, your storefront can do this:
ts
importtype {
B2BCompany,
B2BQuoteRequest,
MedusaPickupSlot,
MedusaReview,
Post,
Page,
} from"@repo/shared-types"
This is much better than importing from .medusa, because:
the contract is stable
the storefront only depends on your shared package
you control which Medusa shapes are exposed
you can evolve the backend without leaking implementation details
The gotchas we found
This is where most implementations go wrong.
Gotcha 1: Medusa does not auto-generate shared monorepo types like Payload does
This was the biggest misunderstanding.
Payload can generate a shared file into packages/shared-types.
Medusa does not do that.
So if you want a shared contract for the storefront, you must maintain it yourself.
Gotcha 2: do not build a sync flow around .medusa/types
We considered a sync-types.sh approach that copied generated Medusa declarations into packages/shared-types.
We removed it.
Why?
it fights Medusa's intended usage
it is easy to copy files that are not portable
it creates unnecessary build ordering issues
it still does not give you a stable public contract
If you are searching for how to share Medusa types in a monorepo with a Next.js storefront, the answer is not "copy .medusa/types into another package."
The answer is "export inferred aliases from your actual Medusa models."
Gotcha 3: your consumer app must actually depend on @repo/shared-types
The storefront in our workspace re-exported from @repo/shared-types, but TypeScript still needs that package declared as a workspace dependency.