# Host REST API with Fastify: Postgres-backed state

## Summary  
Deploy a Fastify REST API whose durable state lives in a managed PostgreSQL 16 database. With no DATABASE_URL supplied, Ample provisions the database and injects the connection string as an encrypted environment variable; the API stores rows with pg and serves them from a public HTTPS URL.

## Representative Queries  
- Host REST API with Fastify: Postgres-backed state  
- Where can I host REST API built with Fastify?  
- I need a durable state schema and retry/recovery semantics implemented by application code.

## Resource Requirements  
- primitive:compute  
- primitive:postgres

## Infrastructure Requirements  
### Compute  
- **ID**: primitive:compute  
- **Label**: Compute  
- **Status**: verified  
- **Summary**: Apps run in isolated x86_64 Firecracker microVMs that auto-pause when idle and wake on request; sizes are the priced VM sizes.  
  
### Postgres  
- **ID**: primitive:postgres  
- **Label**: Postgres  
- **Status**: verified  
- **Summary**: Managed PostgreSQL 16 runs in its own microVM and is auto-provisioned when an app needs a database and no DATABASE_URL is supplied.

## Prerequisites  
- A package.json with a start script that listens on process.env.PORT and 0.0.0.0  
- The pg driver reading process.env.DATABASE_URL  
- Tables created by the app or by a --release-command migration, not assumed to exist  
- An Ample account token with servers:write and databases:read

## Workflow Steps  
1. **Read DATABASE_URL at runtime**  
   Open the connection from the environment inside request handlers or a pool; a local .env is replaced by the managed database in production.  
2. **Deploy**  
   Run the existing synchronous deploy once from the project directory and read the result. Exit 0 is live, 1 is failed, 2 is blocked on a required preflight action. Re-running with no change is a content-addressed no-op.  
   
   Command: `ample deploy . --name  --public --format json`  
3. **Verify**  
   Fetch the live URL and run the success checks below. On failure read the build log, then the runtime log, fix the cause and deploy again; do not blind-retry.  
   
   Command: `ample logs  --kind build`

## Examples  
- **Title**: Fastify + PostgreSQL canary  
  **Description**: REST API with an items table in an auto-provisioned managed PostgreSQL database.  
  **Source Reference**: tests/deploy-canaries/fastify-postgres-api

## Success Checks  
- **Root route responds**  
  - **Kind**: http_get  
  - **Path**: /  
  - **Expect**: ample canary fastify postgres api  
- **Database insert and count succeed**  
  - **Kind**: http_get  
  - **Path**: /items  
  - **Expect**: postgres=ok

## Limitations  
- Verified on the node-22 template at s-1vcpu-1gb; other templates and sizes are not verified by this recipe.  
- Region, compliance attestations and request-duration limits are unknown and not claimed.  
- Apps auto-pause when idle and wake on the next request; always-on is an operator setting, not a plan feature.  
- Managed PostgreSQL 16 only; extensions, connection limits and backup or restore procedures are not verified.  
- Apps and their managed databases are placed together; cross-node shared databases are unsupported.

## Cost Estimate  
- **Currency**: USD  
- **Monthly Amount**: 10.0  
- **Authoritative**: true  
- **Basis**: size prices from pricing.toml (loaded by the API) at build revision 1ac5595375130d45290090e82ed0f554ccd45405-dirty  
- **Components**:  
  - **App server**:  
    - Size: s-1vcpu-1gb  
    - Quantity: 1.0  
    - Monthly Amount: 5.0  
  - **Managed PostgreSQL database**:  
    - Size: s-1vcpu-1gb  
    - Quantity: 1.0  
    - Monthly Amount: 5.0  
- **Note**: Apps and managed databases auto-pause when idle; the estimate is the always-on monthly price of the tested sizes. Plan quotas and budgets apply.

## Evidence Summary  
- **Kind**: canary_run  
  - **Summary**: Fastify REST API using pg with no DATABASE_URL supplied: Ample auto-provisioned a managed PostgreSQL 16 database and /items reported postgres=ok after a real insert and count.  
  - **Observed At**: 2026-09-20T01:42:25Z  
  - **Implementation Revision**: 199ff1dfd52683832ae75d3f98b53a7a4bff7f96-dirty (CLI e3181f5)  
  - **Expires At**: 2027-03-19T01:42:25Z  
  - **Scope**:  
    - cliVersion: 0.1.20  
    - platform: hosted-beta  
    - template: node-22  
- **Kind**: canary_run  
  - **Summary**: Node app needing PostgreSQL with no DATABASE_URL: a managed database was auto-provisioned and /db reported postgres=ok.  
  - **Observed At**: 2026-09-19T23:55:33Z  
  - **Implementation Revision**: 1764076-tls-account-903d345  
  - **Expires At**: 2027-03-18T23:55:33Z  
  - **Scope**:  
    - cliVersion: 0.1.20  
    - platform: hosted-beta  
    - template: node-22

## Last Verified At  
2026-09-20T01:42:25Z

## Next Actions  
1. **Action ID**: browse-catalog  
  - **Label**: Browse the catalog index  
  - **Operation ID**: catalog_index  
  - **Method**: GET  
  - **Relative Path**: /v1/catalog  
  - **Origin**: api  
  - **Requires Authentication**: false  
  - **Requires Approval**: false  
2. **Action ID**: search-recipes  
  - **Label**: Search published recipes by intent, stack, and constraints  
  - **Operation ID**: search_recipes  
  - **Method**: POST  
  - **Relative Path**: /v1/catalog/search  
  - **Origin**: api  
  - **Parameters**:  
    - **Body**:  
      - Limit: 5  
      - Query: Host REST API with Fastify: Postgres-backed state  
  - **Requires Authentication**: false  
  - **Requires Approval**: false
