Skip to content
Security
Skill

/stash-deployment

Deploy a CipherStash encryption rollout to a live environment without losing data — the multi-deploy ladder (schema-add + dual-write → backfill → read cutover → stop dual-writes → drop plaintext), why each deploy boundary exists, what breaks if stages are merged, rollback per

BOOST
From plugin
stack
16116 skills1 command
Install
$ npx -y skills add cipherstash/stack --skill stash-deployment --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/stash-deployment

Context preview

The summary Claude sees to decide when to auto-load this skill.

Deploy a CipherStash encryption rollout to a live environment without losing data — the multi-deploy ladder (schema-add + dual-write → backfill → read cutover → stop dual-writes → drop plaintext), why each deploy boundary exists, what breaks if stages are merged, rollback per

SKILL.md

stash-deployment.SKILL.md
name: stash-deployment
description: Deploy a CipherStash encryption rollout to a live environment without losing data — the multi-deploy ladder (schema-add + dual-write → backfill → read cutover → stop dual-writes → drop plaintext), why each deploy boundary exists, what breaks if stages are merged, rollback per stage, and how to get CS_* credentials into a build and a runtime. Includes a Prisma Postgres / Prisma Compute section covering push-to-deploy, build-time credential requirements, destructive-migration policy, preview-branch databases, and running backfills against a hosted database. Use when shipping encryption to staging or production, planning the PR sequence for an encryption rollout, wiring deploy credentials, or deploying a CipherStash app to Prisma Compute.

Stash Deployment

Encrypting a column that already holds live data is a **deployment problem**, not a schema problem. The schema change is trivial; the danger is the window between "the database can hold ciphertext" and "the application reads ciphertext". Getting that window wrong loses data silently — rows written during the gap keep only plaintext, or keep only ciphertext nobody can decrypt, and nothing errors until a user reads the row.

This skill covers how to sequence that across deploys. For the API and the lifecycle model see `stash-encryption`; for the commands see `stash-cli`; for framework specifics see `stash-drizzle` / `stash-supabase` / `stash-prisma`.

Everything here describes **EQL v3**, the only authoring generation. The EQL v2 rollout commands were removed — `stash encrypt cutover` (the old v2 rename swap) now exits with an error on every project. A column that started under v2 finishes the same way as v3: complete the backfill, switch reads to the encrypted column by name, then `stash encrypt drop`. Legacy v2 payloads remain readable; `stash-encryption` covers that.

> **Runner note.** `stash init` adds `stash` to the project as a dev dependency, > so the bare `stash <command>` form used below runs through whichever package > manager the project uses. Before init has run, prefix with your package > manager's one-shot runner (`bunx`, `pnpm dlx`, `yarn dlx`, `npx`). The same > substitution applies to the `prisma-next` and `@prisma/cli` invocations in the > Prisma section.

When to Use This Skill

  • Planning the PR / deploy sequence for encrypting an existing column
  • Shipping an encryption rollout to staging or production
  • Running a backfill against a hosted (not local) database
  • Getting `CS_*` credentials into a build pipeline and a deployed runtime
  • Deploying a CipherStash app to **Prisma Postgres / Prisma Compute**
  • Diagnosing a failed deploy, a failed migration, or rows that won't decrypt

The rule

> **A column goes from plaintext to encrypted across at least four deploys, never one.**

Not a style preference. There is no atomic operation that replaces a populated plaintext column with an encrypted one, because **ciphertext can only be produced by the application**, client-side, holding your keys. No `UPDATE`, no migration, no database-side function can encrypt an existing row. So the plaintext column must stay authoritative — and stay populated — until every row has a ciphertext twin and the deployed code is reading it.

Any plan that adds an encrypted column and drops the plaintext one in the same deploy loses data. Any plan that backfills before dual-writes are live in production loses the rows written during the backfill. The ladder below is the minimum safe shape.

The deployment ladder

 DEPLOY 1     rollout           + encrypted twin (nullable) + dual-write
                                everywhere; reads unchanged

   ⛔ GATE 1  dual-writes live in the environment that owns the database

 out-of-band  BACKFILL          encrypt historical rows, against the prod DB
 migration    indexes           eql_v3.* extractor indexes + ANALYZE, shipped
                                through the integration's migration flow

 DEPLOY 2     read cutover      reads → encrypted column, decrypt at the
                                boundary; dual-writes stay

   ⛔ GATE 2  soak — real traffic reads decrypt correctly

 DEPLOY 3     stop dual-write   writes → encrypted column only; plaintext
                                column stays, now unwritten

   ⛔ GATE 3  Deploy 3 live everywhere; coverage re-checked

 DEPLOY 4     drop plaintext    drop the plaintext column (+ NOT NULL on
                                encrypted), guarded by an apply-time
                                coverage re-check

Four deploys, with the backfill and index build between the first two. Each gate is a human decision, not a pipeline step.

Deploy 0 — prepare the environment (optional, do it early)

Before any application change, make sure the target environment can encrypt at all:

  • **EQL installed** in the target database. Direct install is `stash eql install`;

**Drizzle** generates an install migration instead (apply it with `drizzle-kit migrate`), and **Prisma Next** installs it through the migration graph (`prisma-next migrate`).

  • **`CS_*` credentials present** in the environment, minted with

`stash env --name <app>-<env>`. On most platforms these are needed at **build** time as well as run time (see [Credentials](#credentials-in-a-deployed-environment)).

  • **Bundling handled.** The default `@cipherstash/stack` entry wraps a native

FFI module — exclude it from bundling (`serverExternalPackages`, esbuild `external`, …). On runtimes that cannot load native modules at all (Cloudflare Workers, Deno, Supabase Edge Functions), bundle `@cipherstash/stack/wasm-inline` instead — it inlines the WASM build, no externalization needed. See `stash-edge`.

Shipping this as its own deploy is cheap and de-risks Deploy 1: a credential or bundling problem surfaces while nothing depends on encryption yet.

Deploy 1 — rollout: encrypted twin + dual-write

One PR, one deploy. It ch

Read more
Ships withstack

Searchable, application-level encryption for building privacy-first apps

Get the whole plugin

Other skills on stack.

stash-auth
Skill

stash-auth

How a CipherStash client authenticates — the canonical skill for credentials, auth strategies, and lock context. Covers the…

stash-cli
Skill

stash-cli

Drive CipherStash setup and encryption migrations through the `stash` CLI — `init`, `plan`, `impl`, `status`, `auth login`, `eql…