Docs CLI & provisioning
Install
Preview what kizunasync init would write, then provision Kizuna into a Supabase project. The pack lands as migration files in your repository, or straight in a hosted project over the Management API.
init emits the installable SQL pack. From your existing Row Level Security policies, it proposes the synced tables. It then generates the migration that fills the server configuration. On the local-file path, init also exposes kizunasync to PostgREST.
Before you begin#
- A Supabase application project to install into. The local-file path needs a
supabase/config.toml, so runsupabase initandsupabase linkfirst. Supabase covers both in Local development, and Kizuna adds no project of its own on top. - Row Level Security policies on the tables you want
initto propose. Kizuna reads them to guess an owner column, never to write or change a policy. A flag-only or--local-onlyrun cannot read them, so you edit those table entries by hand afterwards. - Run every command from the application project, or pass
--workdir <path>, which Project root explains.
npx kizunasync --helppnpm dlx kizunasync --helpyarn dlx kizunasync --helpbunx kizunasync --helpYou should now see the command list, with init, sync, status, doctor, lint, upgrade, deprovision, jobs, mock, and version. The CLI reference describes each one.
1. Preview the local-file path#
npx kizunasync init --dry-run --db-url "$KSYNC_DB_URL"pnpm dlx kizunasync init --dry-run --db-url "$KSYNC_DB_URL"yarn dlx kizunasync init --dry-run --db-url "$KSYNC_DB_URL"bunx kizunasync init --dry-run --db-url "$KSYNC_DB_URL"The dry run reads your policies, prints the pack and config plan, and writes nothing at all. You should now see the SQL pack and the generated project-config SQL on stdout, with no new file in supabase/migrations/.
Any host that is not loopback connects over TLS, with the certificate and the hostname verified, so the connection strings the Supabase dashboard's Connect panel shows work as they are. Kizuna decides TLS before the connection opens and refuses sslmode=disable or sslmode=allow on such a host. Supabase covers the parameter in Connecting with SSL. Take the string from your project's Supabase settings rather than assembling one, since pooler endpoints are project-specific. Database connection lists every place the CLI looks for it.
2. Apply the local-file path#
npx kizunasync init --yes --db-url "$KSYNC_DB_URL"pnpm dlx kizunasync init --yes --db-url "$KSYNC_DB_URL"yarn dlx kizunasync init --yes --db-url "$KSYNC_DB_URL"bunx kizunasync init --yes --db-url "$KSYNC_DB_URL"This writes timestamped migrations, one of which upserts your synced tables into kizunasync._config. It patches [api].schemas in supabase/config.toml and runs supabase db push. To write the files without connecting or applying, run init --local-only --yes instead.
You should now see the new migrations in supabase/migrations/ and kizunasync in the [api].schemas list. What Kizuna installs is the inventory those migrations create.
A config migration already in the folder is skipped rather than emitted twice. Kizuna's SQL becomes ordinary migration files, so Supabase's migration tracking records them like your own. --local-only --yes skips policy introspection, so that mode cannot propose tables from the database.
3. Use the wizard instead#
npx kizunasync initpnpm dlx kizunasync inityarn dlx kizunasync initbunx kizunasync initOn a real terminal, with no --yes, --local-only, or --dry-run, init asks instead of assuming. It settles a connection, asks which tables to sync, offers Recommended or Customize, and ends on one write confirmation that defaults to no. Customize walks the per-table contract, the server maintenance schedules, the push policy, and what to do when pg_cron is absent.
The connection question appears only when no --db-url and no connection-string variable in the process environment already picked one. It then offers what it found: the linked project, named by SUPABASE_PROJECT_ID or by the ref supabase link recorded, connection strings declared in the project's .env files, the local Supabase stack, and a project from your Supabase account, always offered last. Once you pick one, Kizuna tests it and reports what it found; a failed test explains why and offers the list again. Interactive mode documents each prompt.
When you choose an account project, Kizuna resolves a Personal Access Token in a fixed order. It reads the --access-token flag first, then SUPABASE_ACCESS_TOKEN, then the same key in the project's .env files. It reads the operating system keyring the Supabase CLI writes next, under the current profile's account and then the legacy access-token account, and the access-token file in the Supabase home directory (SUPABASE_HOME, else ~/.supabase) last. Kizuna only reads a token you already have. When no source resolves, the wizard runs supabase login. A missing CLI or a cancelled login falls back to a masked paste that Kizuna keeps in memory only. A run that never selects an account project never reads the keyring.
The wizard's step titles may render as clickable links in terminals that support OSC 8. That presentation changes neither the scripted contract nor what gets written.
You should now see the plan, and then either the same files step 2 produces or a clean cancellation that wrote nothing.
4. Provision a hosted project through the Management API#
Set SUPABASE_ACCESS_TOKEN in the environment first. kizunasync reads it there, which keeps the token out of the command line and the process list.
npx kizunasync init \
--project-ref <project-ref> \
--dry-run
npx kizunasync init \
--project-ref <project-ref> \
--yespnpm dlx kizunasync init \
--project-ref <project-ref> \
--dry-run
pnpm dlx kizunasync init \
--project-ref <project-ref> \
--yesyarn dlx kizunasync init \
--project-ref <project-ref> \
--dry-run
yarn dlx kizunasync init \
--project-ref <project-ref> \
--yesbunx kizunasync init \
--project-ref <project-ref> \
--dry-run
bunx kizunasync init \
--project-ref <project-ref> \
--yesThis path reads and updates the hosted PostgREST schema configuration. It runs the same table proposal and the same wizard the local path runs. It introspects your tables through the Management API rather than a direct Postgres connection. The command then applies each pack file and the config SQL through the Management API's run a query endpoint. It never calls db push, so the SQL leaves no trace in your migration history. You accept that in exchange for provisioning a project with no local supabase/ directory. The credential is a Personal Access Token, never one of your project's own keys. It is not a publishable key, and it is not a secret key. The token travels only in the Authorization header. --project-ref conflicts with --local-only and --db-url, and exits 2 against either.
You should now see the exposure outcome and the pack plan from the dry run, then a report of what the kizunasync._provisions ledger holds after the apply. Remote provisioning lists the four outcomes that ledger can produce.
5. Verify#
npx kizunasync doctor
npx kizunasync status --db-url "$KSYNC_DB_URL"pnpm dlx kizunasync doctor
pnpm dlx kizunasync status --db-url "$KSYNC_DB_URL"yarn dlx kizunasync doctor
yarn dlx kizunasync status --db-url "$KSYNC_DB_URL"bunx kizunasync doctor
bunx kizunasync status --db-url "$KSYNC_DB_URL"doctor reads kizunasync._config over the same connection ladder status uses, checks the local project files, and adds one live Data API probe when it finds a project URL and a publishable key, from the flags, the environment, your .env files, or the linked project. status reads provisioned state through Postgres, or through the Management API with --project-ref.
You should now see every doctor check passing, including config-tables, which names how many synced tables the database declares, and api-schemas, which catches a schema missing from the exposed list. The status report should show a pack line that is up to date and a tables section listing the tables you provisioned.
Neither command proves that your application tables' policies are correct. Test authorization separately, against the policies Supabase documents in Row Level Security, and read Server-side validation for what the server decides after a write is queued.
Next steps#
Found a problem? Edit this page on GitHub