Remote State
By default Kyku writes state to .kyku/state.<env>.json. To share state across machines or CI jobs, set a remote backend in the config file.
Configure
Section titled “Configure”export default { provider: 'aws', backend: { type: 's3', bucket: 'kyku-state', region: 'us-east-1', key: 'prod/state.json', }, resources: [/* ... */],};export default { provider: 'gcp', backend: { type: 'gcs', bucket: 'kyku-state', key: 'prod/state.json', }, resources: [/* ... */],};DigitalOcean Spaces
Section titled “DigitalOcean Spaces”export default { provider: 'digitalocean', backend: { type: 'spaces', bucket: 'kyku-state', region: 'nyc3', key: 'prod/state.json', }, resources: [/* ... */],};Spaces reuses the S3 manager with endpoint https://<region>.digitaloceanspaces.com.
export default { provider: 'hetzner', backend: { type: 'http', address: 'https://state.example.com/prod/state.json', // lockAddress: 'https://state.example.com/prod/state.lock', }, resources: [/* ... */],};GET retrieves state (404 = empty). PUT writes with If-Match / If-None-Match. The lock is a second JSON object at lockAddress (default ${address}.lock). Auth is optional until the server returns 401: KYKU_HTTP_TOKEN (Bearer) or KYKU_HTTP_USERNAME + KYKU_HTTP_PASSWORD (Basic).
There are no CLI flags for backend settings. plan, apply, and destroy pick the block up from infrastructure.ts (or -c).
Behaviour
Section titled “Behaviour”- Load and save target that single object. Writes are conditional (
If-Match/If-None-Matchon S3 and HTTP,ifGenerationMatchon GCS) so two writers cannot clobber each other. - Each successful save increments
serial. A write whose in-memory serial no longer matches the remote object is refused. - The lock lives at
${key}.lockin the same bucket (s3://…,gs://…, orspaces://…) or atlockAddressfor HTTP, with the same 60s heartbeat and token-conditional stale break as the local lock. - Missing S3/GCS/Spaces credentials are a hard error. HTTP allows unauthenticated calls until the server returns 401. Kyku does not write local state instead.
Migrating existing local state
Section titled “Migrating existing local state”kyku state push uploads .kyku/state.<env>.json to the configured object, verifies the round-trip, and renames the local file to .migrated. It refuses if remote state already exists unless you pass --force. The next kyku plan reads from the remote backend.
Plan and apply never auto-migrate. Opt in on plan with --migrate-state (error if remote exists) or --force-migrate (overwrite). There is no backend.autoMigrate and no bare --force. A leftover .migrated file is never re-uploaded.
Out of scope
Section titled “Out of scope”There is no state pull / state sync, no backend-to-backend move, no bucket create, and no state version browsing.
Credentials
Section titled “Credentials”export AWS_ACCESS_KEY_ID=...export AWS_SECRET_ACCESS_KEY=...export AWS_SESSION_TOKEN=... # temporary / STS creds# or: AWS_PROFILE, instance role, or AWS_WEB_IDENTITY_TOKEN_FILEexport GOOGLE_CLOUD_PROJECT=...export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json# or: gcloud auth application-default login# or: KYKU_GCP_WORKLOAD_PROVIDER + KYKU_GCP_SERVICE_ACCOUNTDigitalOcean Spaces
Section titled “DigitalOcean Spaces”export DO_SPACES_REGION=nyc3export DO_SPACES_ACCESS_KEY=...export DO_SPACES_SECRET_KEY=...export KYKU_HTTP_TOKEN=...# or:export KYKU_HTTP_USERNAME=...export KYKU_HTTP_PASSWORD=...