Appearance
Lifecycle & Hooks
Nanokit provides an engine to manage the lifecycle of your services, from the initial provisioning of dependencies to graceful teardown.
Understanding these hooks is essential for managing database migrations, complex build steps, and service discovery updates.
Hooks are free-form shell
Every field on this page takes an arbitrary shell command. Together with services.*.start, services.*.command and cron.*.command, they are why write access to nanokit.yml is equivalent to command-execution rights — on your machine and, for deploy.prepare, on every deploy target.
Provisioning Hook (provisioning.install)
The provisioning.install command is designed for one-time initialization of a service. It is specifically optimized for distributed environments where multiple replicas might share the same persistent storage.
How it works
- Host-Side Execution: The command runs on the host (or inside a temporary bootstrap container) before the service containers start.
- Atomic Locking: Nanokit uses a sentinel file located in the service's primary volume to track installation status.
- Prevention of Race Conditions: If multiple replicas or environments share the same volume, Nanokit ensures only one process performs the installation.
yaml
services:
api:
runtime: node
provisioning:
# Executed only once if node_modules is missing or sentinel is absent
# Can also be defined globally in the 'node' runtime
install: "npm install --prefer-offline"Tip. Use
provisioning.installfor heavy operations likenpm install,composer install, or downloading large binary dependencies that should persist across container restarts.To force it to run again after a corrupted install, use
nkapp up --reprovision— it cache-busts the sentinel.
Service Hooks (hooks)
Service hooks are executed relative to the container lifecycle. These are defined under the hooks key in your service configuration.
| Phase | Context | Typical Use Case |
|---|---|---|
prestart | Host/Provider | Database migrations (prisma migrate), build steps (nx build), config generation. |
poststart | Host/Provider | Warm-up scripts, registration in external service discovery. |
prestop | Container | Graceful session flushing, unregistering from load balancers. |
poststop | Host/Provider | Cleanup of temporary files, logging teardown events. |
Example: Database Migrations
The prestart hook is the recommended place for running database migrations. Nanokit ensures all required databases are up and healthy before triggering the hook.
yaml
services:
web:
runtime: node
hooks:
prestart: "npx prisma migrate deploy"Example: Build Step Before Container Start
Services that run compiled output (e.g. node dist/...) need their source built before the container can start. Use prestart to auto-build these services — this is especially useful for containerized backend services where the Docker image runs pre-compiled JavaScript.
yaml
services:
api-gateway:
runtime: node
start: node dist/apps/api-gateway/main.js
hooks:
prestart: "npx nx build api-gateway --skip-nx-cache"The prestart hook runs on the host before the container is created, ensuring the compiled output is ready when the container starts. This approach keeps build tooling (Nx, Webpack, TypeScript) out of the container image, resulting in leaner production images.
Tip. For monorepo backends, define a
prestartbuild hook on each service that runs fromdist/. Nanokit executes these hooks automatically duringnkapp up, eliminating the need for manual rebuilds.
Example: Post-Startup Notification
You can use poststart to trigger external webhooks or internal logging once a service is live.
yaml
services:
worker:
runtime: node
hooks:
poststart: "curl -X POST https://status.internal/v1/event -d '{\"service\": \"worker\", \"status\": \"online\"}'"Deployment Hooks
While service hooks manage the container lifecycle, deployment hooks manage the orchestration process itself.
deploy.prepare
Where prepare runs depends on the target
- VPS / Docker-over-SSH targets —
prepareruns on the remote host, inside an isolated runtime container, after the code sync and before the reconcile. The build happens on the server. - Cloud provider targets (AWS / GCP / Azure / DigitalOcean) —
prepareruns locally (on your machine or the CI runner), because that local build produces the image content that is then pushed to the registry.
yaml
deploy:
target: root@my-vps
prepare: npm ci && npm run buildThe services placeholder
Because nkapp deploy is change-proportional, you usually only want to build the services actually being deployed. The literal token {{services}} is replaced everywhere it occurs with the in-scope service names joined by ,:
yaml
deploy:
prepare: npm install --prefer-offline && npx nx run-many -t build --projects=shared,{{services}} --parallel=1- A command without the token runs verbatim — the placeholder is fully opt-in.
- Under a full deploy it expands to the environment's complete service list; never to the literal token, never to the empty string.
- It expands to services only. Non-service projects that must always build (shared libraries, submodule packages) stay explicit in the command.
- Per-service
buildProject:controls the contribution: a string substitutes a different build-tool project name;falseexcludes the service entirely (for static apps and pure images).
Full detail in the nkapp deploy reference.
Environment Variables in Hooks
All hooks have access to standard Nanokit environment variables, allowing you to create context-aware scripts:
NANOKIT_SERVICE: Name of the current service.NANOKIT_ENV: Current environment (e.g.,stage,prod).NANOKIT_PROJECT: Name of the project.LIFECYCLE_PHASE: The name of the hook being executed.
Best Practices
- Idempotency: Ensure hooks can be run multiple times without side effects (especially
prestart). - Keep them short.
nanokit.ymlis declarative config, not a place for logic. Push non-trivial behaviour (waiting, ordering, conditionals) into a script the hook calls, so the config stays reviewable. - Timeouts: Hooks that run for too long can block deployments. Offload heavy async tasks to background workers if possible.
- Error Handling: Non-zero exit codes in
prestartorprovisioning.installwill halt the deployment for that service.