native-components.json
Where components go, how they import each other, and which app to wire up.
Written by init, next to your components. The nearest one wins, walking up from --cwd.
{
"$schema": "https://raw.githubusercontent.com/delacournz/delacour-ui/main/registry/config.schema.json",
"framework": "expo",
"typescript": true,
"registry": {},
"registries": {},
"paths": {
"ui": "src/components/ui",
"lib": "src/lib",
"hooks": "src/hooks",
"styles": "src/styles",
"icons": "src/lib/icons"
},
"aliases": {
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks",
"styles": "@/styles",
"icons": "@/lib/icons"
},
"app": {
"root": ".",
"css": "src/styles/global.css",
"metroConfig": "metro.config.js",
"uniwindTypes": "src/uniwind-types.d.ts"
}
}The $schema URL is generated from the same definitions the CLI validates against, so editor
completions cannot describe a shape the CLI would then reject.
paths and aliases are not the same thing
This is the one part of the file worth understanding. They answer two different questions:
paths— where a file lands on disk, relative tonative-components.json.aliases— what other files import it as.
They coincide only when the project has path aliases configured. Many Expo apps do not, and Metro
resolves tsconfig paths only with experiments.tsconfigPaths turned on. Keeping them separate
means two things: add never has to parse a tsconfig to work out where anything went, and a
project with no aliases at all still gets imports that resolve.
An empty aliases object is a valid configuration
Leave a namespace out and imports into it are written as relative paths, computed from where
the files actually landed. Delete aliases entirely and every import is relative.
// aliases.ui set
import { Icon } from "@/components/ui/icon";
// aliases.ui absent
import { Icon } from "../icon";init fills aliases in by reading a wildcard mapping like "@/*": ["./src/*"] out of
tsconfig.json. It never writes to that file.
The five namespaces
Prop
Type
package
{ "package": { "name": "@acme/ui" } }Present only when the components live in a shared package, and written by init when you name one.
Its presence is what makes add maintain the package's exports map and record native modules as
peers — see Monorepos.
Prop
Type
app
Which Expo app to wire up. Every path here is relative to app.root, and app.root itself is
relative to native-components.json.
Prop
Type
This block exists because the components and the app are not always the same package. Metro, the Tailwind entry and the native dependencies always belong to the app, even when the components live in a shared package — see Monorepos.
registry
{
"registry": { "ref": "v0.2.0" }
}Prop
Type
Covered in The registry.
The rest
Prop
Type
Changing it later
Edit the file and re-run add for anything already copied — the CLI writes to whatever paths
says now, so old files stay where they were. delacour info prints the resolved absolute paths,
which is the quickest way to check a change landed the way you meant.