Agent skill

Deployment Gotchas

by j-morgan6 in j-morgan6/elixir-phoenix-guide

A skill your agent uses when preparing releases or deployment config — runtime.exs vs compile-time config, release migrations, PHXHOST/PHXSERVER, assets, health checks.

MITAuto-check passedDevOps & Cloud

Install Deployment Gotchas

skills CLI
$ npx skills add j-morgan6/elixir-phoenix-guide --skill deployment-gotchas -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install j-morgan6/elixir-phoenix-guide deployment-gotchas --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/j-morgan6/elixir-phoenix-guide.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/deployment-gotchas .claude/skills/deployment-gotchas && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
deployment-gotchas
GitHub stars
166
Token cost
~2.6k tokens
SKILL.md length
789 words
Files
1
Skills in repo
19
Repo updated
First seen
Licence
MIT

At a glance

A skill your agent uses when preparing releases or deployment config — runtime.exs vs compile-time config, release migrations, PHXHOST/PHXSERVER, assets, health checks.

  • Works in 7 steps: runtime.exs vs config.exs → Release Migrations → PHX_HOST and PHX_SERVER → …
  • Preparing releases
  • SKILL.md covers RULES — Follow these with no…, 1. runtime.exs vs config.exs, 2. Release Migrations and 3. PHX_HOST and PHX_SERVER, plus 5 more sections
  • Calls ssh

What it does

Deployment Gotchas is an agent skill from j-morgan6/elixir-phoenix-guide. Use when preparing releases or deployment config — runtime.exs vs compile-time config, release migrations, PHXHOST/PHXSERVER, assets, health checks.

Its SKILL.md is about 2.6k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in DevOps & Cloud, covering Deployment. The licence is MIT.

When your agent uses it

  • Preparing releases
  • Deployment config — runtime.exs vs compile-time config
  • Release migrations
  • PHXHOST/PHXSERVER

Example prompts

  • “/deployment-gotchas”

Requirements

  • Docker

Workflow steps

7 steps, taken from the step headings in SKILL.md.

  1. runtime.exs vs config.exs
  2. Release Migrations
  3. PHX_HOST and PHX_SERVER
  4. Asset Deployment
  5. Never Hardcode Secrets
  6. Health Endpoints
  7. Production Log Level

What it can do on your machine

Read from SKILL.md and the folder at commit cdfddac. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • ssh

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use ssh, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Deployment Gotchas loads about 2.6k tokens when it runs. Until then it costs about 42 tokens; SKILL.md has 789 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~42
When it runs · the whole SKILL.md, loaded when a task matches
~2.6k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from j-morgan6/elixir-phoenix-guide at commit cdfddac, republished under its MIT licence (© j-morgan6). 789 words, ~2,553 tokens.

Download SKILL.mdSave it as .claude/skills/deployment-gotchas/SKILL.md (or your agent's skills folder).
name
deployment-gotchas
description
Use when preparing releases or deployment config — runtime.exs vs compile-time config, release migrations, PHX_HOST/PHX_SERVER, assets, health checks.
file_patterns
**/config/*.exs, **/rel/**, **/Dockerfile, **/docker-compose*.yml
auto_suggest
true

Deployment Gotchas

Not a deployment guide — these are the 7 things that break every first Phoenix deploy. Every rule maps to a real production incident pattern.

RULES — Follow these with no exceptions

  1. Use runtime.exs for secrets and URLs — config.exs/prod.exs are compiled into the release and cannot read env vars at boot
  2. Run migrations via release commands (bin/migrate) — mix is not available in production releases
  3. Set PHX_HOST and PHX_SERVER=true — without these, URL generation breaks and the server won't start
  4. Run mix assets.deploy before building the release — forgetting this means no CSS/JS in production
  5. Never hardcode secrets — use System.fetch_env!/1 in runtime.exs (the ! crashes on boot if missing, which is what you want)
  6. Split health checks into liveness and readiness — liveness returns 200 without touching the DB; only readiness queries the database
  7. Use config :logger, level: :info in production — :debug logs query parameters including user data

1. runtime.exs vs config.exs

The incident: App deploys fine but uses the wrong database URL. DATABASE_URL was set correctly in the environment, but the release ignores it.

Why: config.exs and prod.exs are evaluated at compile time and baked into the release. runtime.exs is evaluated at boot time and can read environment variables.

Bad:

elixir
# config/prod.exs — compiled into release, cannot read env vars at boot
config :my_app, MyApp.Repo,
  # Evaluated at BUILD time — captures the build machine's env, not the
  # runtime env. Silently wrong in a release; use runtime.exs instead.
  url: System.get_env("DATABASE_URL")

Good:

elixir
# config/runtime.exs — evaluated at boot, reads env vars correctly
if config_env() == :prod do
  database_url = System.fetch_env!("DATABASE_URL")

  config :my_app, MyApp.Repo,
    url: database_url,
    pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10")
end

Rule of thumb: If the value comes from the environment, it goes in runtime.exs. If it's a static setting, it goes in config.exs.


2. Release Migrations

The incident: Deploy succeeds but the app crashes on boot because new columns don't exist. Developer tries mix ecto.migrate on the server — mix: command not found.

Why: Production releases don't include Mix or the Elixir compiler. Migrations must be run via release commands.

Bad:

bash
# mix is not available in production releases
ssh prod-server "cd /app && mix ecto.migrate"

Good:

elixir
# lib/my_app/release.ex
defmodule MyApp.Release do
  @app :my_app

  def migrate do
    load_app()

    for repo <- repos() do
      {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
    end
  end

  def rollback(repo, version) do
    load_app()
    {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version))
  end

  defp repos do
    Application.fetch_env!(@app, :ecto_repos)
  end

  defp load_app do
    Application.ensure_all_started(:ssl)
    Application.load(@app)
  end
end
bash
# Run migrations in production
bin/my_app eval "MyApp.Release.migrate()"

# Or via rel/overlays if configured
bin/migrate

3. PHX_HOST and PHX_SERVER

The incident: Deploy succeeds, health check passes, but all URLs in emails and redirects point to localhost:4000. Or worse — the server doesn't start at all.

Why: Without PHX_SERVER=true, the Phoenix endpoint doesn't start its HTTP listener. Without PHX_HOST, URL helpers generate localhost URLs.

Bad:

elixir
# config/runtime.exs — missing host and server config
config :my_app, MyAppWeb.Endpoint,
  url: [host: "localhost"],  # Wrong in production!
  http: [port: 4000]
  # Server doesn't start without server: true

Good:

elixir
# config/runtime.exs
if config_env() == :prod do
  host = System.fetch_env!("PHX_HOST")
  port = String.to_integer(System.get_env("PORT") || "4000")

  config :my_app, MyAppWeb.Endpoint,
    url: [host: host, port: 443, scheme: "https"],
    http: [ip: {0, 0, 0, 0}, port: port],
    server: true  # Or set PHX_SERVER=true env var
end

4. Asset Deployment

The incident: App deploys, pages load, but CSS/JS are missing. The page is unstyled raw HTML.

Why: Assets must be compiled and digested before the release is built. The release bundles priv/static — if assets aren't there at build time, they won't be in the release.

Bad:

dockerfile
# Dockerfile — builds release without compiling assets
RUN mix release

Good:

dockerfile
# Dockerfile — correct order
RUN mix assets.deploy
RUN mix release
bash
# Manual build order
mix deps.get --only prod
MIX_ENV=prod mix compile
MIX_ENV=prod mix assets.deploy  # Must come before release
MIX_ENV=prod mix release

What mix assets.deploy does:

  1. Runs tailwind and esbuild to compile CSS/JS
  2. Runs phx.digest to fingerprint files for cache busting
  3. Generates cache_manifest.json for the endpoint to serve

5. Never Hardcode Secrets

The incident: Secret key leaks into git history via config/prod.exs. Rotating it requires a new release.

Why: Secrets in compiled config are baked into the release binary and visible in version control.

Bad:

elixir
# config/prod.exs — secret in source code
config :my_app, MyAppWeb.Endpoint,
  secret_key_base: "actual_secret_key_here_in_git_history"

Good:

elixir
# config/runtime.exs — read from environment, crash if missing
if config_env() == :prod do
  secret_key_base = System.fetch_env!("SECRET_KEY_BASE")

  config :my_app, MyAppWeb.Endpoint,
    secret_key_base: secret_key_base
end

Why fetch_env! (with bang): If the secret is missing, the app crashes immediately on boot with a clear error. Plain System.get_env/1 returns nil when missing and fails later with a confusing error.

bash
# Generate a secret
mix phx.gen.secret

# Set in environment (never in source)
export SECRET_KEY_BASE="generated_secret_here"

Show full SKILL.md (316 more words)Show less

6. Health Endpoints

The incident: Load balancer reports the app is healthy, but users see 500 errors. The app boots fine but can't connect to the database.

Why: A simple 200 OK endpoint proves the HTTP server started but nothing else. A health check that queries the database proves the full stack works.

Bad:

elixir
# Just proves the server started
get "/health", PageController, :health

def health(conn, _params) do
  send_resp(conn, 200, "OK")
end

Liveness vs readiness: a load balancer liveness probe should return 200 without touching the database — a transient DB blip must not remove the whole fleet. Point deep checks (DB query below) at a readiness probe only.

Good:

elixir
# router.ex
get "/health/live", HealthController, :live
get "/health/ready", HealthController, :ready

# lib/my_app_web/controllers/health_controller.ex
defmodule MyAppWeb.HealthController do
  use MyAppWeb, :controller

  # Liveness: proves the BEAM is up and the endpoint is responding.
  # No DB query — a slow/unavailable database must not take down the
  # whole fleet just because one instance can't reach it.
  def live(conn, _params) do
    send_resp(conn, 200, "OK")
  end

  # Readiness: proves this instance can actually serve traffic.
  def ready(conn, _params) do
    case Ecto.Adapters.SQL.query(MyApp.Repo, "SELECT 1") do
      {:ok, _} ->
        json(conn, %{status: "ok", database: "connected"})

      {:error, reason} ->
        conn
        |> put_status(:service_unavailable)
        |> json(%{status: "error", database: inspect(reason)})
    end
  end
end

Configure your load balancer with two probes: liveness at /health/live (restart the instance if this fails) and readiness at /health/ready (stop routing traffic to this instance if this fails, but don't restart it — the rest of the fleet may still be healthy). Collapsing both into one /health endpoint means a DB blip either gets masked (if it's a shallow check) or takes healthy instances out of rotation right when the DB needs the load to drop (if it's a deep check without the liveness/readiness split).


7. Production Log Level

The incident: App runs fine but storage costs spike. Investigation reveals debug logs are writing gigabytes per day, including full SQL queries with user data (emails, addresses).

Why: Ecto logs all queries at :debug level, including query parameters. In production, this means PII in your logs.

Bad:

elixir
# config/prod.exs
config :logger, level: :debug  # Logs everything including query params

Good:

elixir
# config/prod.exs
config :logger, level: :info

# config/runtime.exs — allow override for debugging
if config_env() == :prod do
  log_level =
    case System.get_env("LOG_LEVEL") do
      "debug" -> :debug
      "warning" -> :warning
      "error" -> :error
      _ -> :info
    end

  config :logger, level: log_level
end

What each level includes:

  • :debug — SQL queries with parameters, internal state, PII risk
  • :info — Request lifecycle, business events (recommended for production)
  • :warning — Recoverable problems
  • :error — Failures requiring attention

Not Covered (Intentionally)

This skill does not cover platform-specific deployment:

  • Docker/Dockerfile patterns → see official Phoenix deployment guides
  • Fly.io, Gigalixir, Render setup → see platform documentation
  • Kubernetes manifests → see your infra team's docs
  • CI/CD pipeline configuration → project-specific

These are deployment-platform docs, not Phoenix-specific gotchas.


See telemetry-essentials skill for production logging and observability patterns. See security-essentials skill for secrets management and dependency auditing.

© j-morgan6, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in skills/deployment-gotchas of j-morgan6/elixir-phoenix-guide.

Open the folder on GitHubat commit cdfddac

Compare with similar skills

Deployment Gotchas next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Deployment Gotchas compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Deployment Gotchas this skillj-morgan6/elixir-phoenix-guide166—~2.6kAutomated safety check: PassMIT
Kubeshark Installerkubeshark/kubeshark12k—~3.6kAutomated safety check: NotesApache-2.0
GreptimeDB Dev Docker ImageGreptimeTeam/greptimedb6.7k—~4kAutomated safety check: NotesApache-2.0
KubeSphere ServiceMesh Managerkubesphere/kubesphere17k—~2.4kAutomated safety check: PassCustom licence
Vercelremotion-dev/remotion63k—~1.2kAutomated safety check: PassCustom licence
AWS Cdk Developmentzxkane/aws-skills3672 repos~2.5kAutomated safety check: PassMIT

Similar skills

  • Kubeshark Installer

    kubeshark/kubeshark

    Installs and configures Kubeshark on a Kubernetes cluster, choosing between the quick CLI path and a Helm install with custom values.

    12k GitHub stars~3.6k tokensUpdated 2 days ago
    DevOps & CloudAuto-check: notes
  • GreptimeDB Dev Docker Image

    GreptimeTeam/greptimedb

    Packages a locally built GreptimeDB debug binary into a development-only Docker image for local-cluster testing, with an optional push to a dev registry.

    6.7k GitHub stars~4k tokensUpdated today
    DevOps & CloudAuto-check: notes
  • KubeSphere ServiceMesh Manager

    kubesphere/kubesphere

    Installs, checks and troubleshoots the KubeSphere ServiceMesh extension (Istio, Kiali, Jaeger), including grayscale release, sidecar injection, topology and tracing issues.

    17k GitHub stars~2.4k tokensUpdated 2 mo ago
    DevOps & CloudAuto-check passed
  • Vercel

    remotion-dev/remotion

    Official

    Set up a Codex monitor for Vercel deployments and preview URLs.

    63k GitHub stars~1.2k tokensUpdated today
    DevOps & CloudAuto-check passed
  • AWS Cdk Development

    zxkane/aws-skills

    AWS Cloud Development Kit (CDK) expert for building cloud infrastructure with TypeScript/Python.

    367 GitHub starsUsed in 2 repos~2.5k tokens
    DevOps & CloudAuto-check passed
  • Senior DevOps Toolkit

    maslennikov-ig/claude-code-orchestrator-kit

    Comprehensive DevOps skill for CI/CD, infrastructure automation, containerization, and cloud platforms (AWS, GCP, Azure). Includes pipeline setup…

    260 GitHub starsUsed in 6 repos~1.1k tokens
    DevOps & CloudAuto-check: notes

More from j-morgan6/elixir-phoenix-guide

All 19 skills in this repo
  • Code Quality

    j-morgan6/elixir-phoenix-guide

    A skill your agent uses when refactoring for duplication, complexity, or dead code — includes the plugin's on-demand analysis scripts.

    166 GitHub stars~1.4k tokensUpdated 3 mo ago
    Auto-check passed
  • Ecto Changeset Patterns

    j-morgan6/elixir-phoenix-guide

    A skill your agent uses when a resource needs multiple changesets (registration vs update), conditional validation, field transforms, or uniqueness validation — changeset composition.

    166 GitHub stars~2.1k tokensUpdated 3 mo ago
    Auto-check passed
  • Ecto Essentials

    j-morgan6/elixir-phoenix-guide

    A skill your agent uses when defining schemas, writing queries, or creating migrations — schema design, Repo usage, indexes, query composition.

    166 GitHub stars~2.2k tokensUpdated 3 mo ago
    Auto-check passed
  • Ecto Nested Associations

    j-morgan6/elixir-phoenix-guide

    A skill your agent uses when a form or operation manages parent and child records together — castassoc/castembed, onreplace, Ecto.Multi across tables, FK cascade design.

    166 GitHub stars~2.2k tokensUpdated 3 mo ago
    Auto-check passed
  • Elixir Essentials

    j-morgan6/elixir-phoenix-guide

    A skill your agent uses when writing or refactoring core Elixir — pattern matching, case/cond/with, pipes, {:ok, }/{:error, } contracts.

    166 GitHub stars~2.2k tokensUpdated 3 mo ago
    Auto-check passed
  • Oban Essentials

    j-morgan6/elixir-phoenix-guide

    A skill your agent uses when writing background jobs with Oban — worker options, return contracts, idempotency, uniqueness, Oban.Testing.

    166 GitHub stars~2.1k tokensUpdated 3 mo ago
    Auto-check passed

Categories

Questions about Deployment Gotchas

What does Deployment Gotchas do?

A skill your agent uses when preparing releases or deployment config — runtime.exs vs compile-time config, release migrations, PHXHOST/PHXSERVER, assets, health checks. Deployment Gotchas is an agent skill from j-morgan6/elixir-phoenix-guide.exs vs compile-time config, release migrations, PHXHOST/PHXSERVER, assets, health checks.

When should I use Deployment Gotchas?

Deployment Gotchas fits situations like: preparing releases; deployment config — runtime.exs vs compile-time config; release migrations; PHXHOST/PHXSERVER.

How do I install Deployment Gotchas in Claude Code?

Run `npx skills add j-morgan6/elixir-phoenix-guide --skill deployment-gotchas -a claude-code`. Or copy the skill folder (skills/deployment-gotchas in j-morgan6/elixir-phoenix-guide) into .claude/skills/deployment-gotchas in your project. Claude Code loads it when a task matches its description.

How do I install Deployment Gotchas in Codex?

Run `npx skills add j-morgan6/elixir-phoenix-guide --skill deployment-gotchas -a codex`. Or copy the skill folder (skills/deployment-gotchas in j-morgan6/elixir-phoenix-guide) into .agents/skills/deployment-gotchas in your project. Codex loads it when a task matches its description.

Can I use Deployment Gotchas in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add j-morgan6/elixir-phoenix-guide --skill deployment-gotchas -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/deployment-gotchas, .gemini/skills/deployment-gotchas, .github/skills/deployment-gotchas and .opencode/skills/deployment-gotchas in your project.

What does Deployment Gotchas need to run?

Going by SKILL.md and its folder, Deployment Gotchas needs the command-line tools its instructions call (ssh). Our summary lists: Docker.

Does Deployment Gotchas access the network?

SKILL.md contains no URLs. Its commands use ssh, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is Deployment Gotchas safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Deployment Gotchas use?

Deployment Gotchas is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Deployment Gotchas use?

About 2.6k tokens (SKILL.md is roughly 10k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Deployment Gotchas?

Skills that share tags, products or a category with Deployment Gotchas: Kubeshark Installer (kubeshark/kubeshark, 12k stars), GreptimeDB Dev Docker Image (GreptimeTeam/greptimedb, 6.7k stars), KubeSphere ServiceMesh Manager (kubesphere/kubesphere, 17k stars) and Vercel (remotion-dev/remotion, 63k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Deployment Gotchas?

j-morgan6 (a GitHub user) maintains it in j-morgan6/elixir-phoenix-guide, which has 166 GitHub stars. The repository holds 19 skills in this directory. The repository was last updated on July 6, 2026.

Source: j-morgan6/elixir-phoenix-guide on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.