name: blockscout description: Blockscout blockchain explorer deployment safety, Helm chart configuration, database migration, microservice patterns, and operational troubleshooting. Use when working with Blockscout backend, frontend, Rust microservices, or blockscout-stack Helm charts.
Blockscout Skill
Version Compatibility
- Chart v4.x requires backend >= 9.2.0 (distributed Elixir, NFT storage restructured)
- Chart v3.x requires backend >= 8.0.0 (Docker registry moved to GHCR, API-only image removed)
- Stats chart image pinned to v2.4.0 by default — verify compatibility when overriding
- When enabling user-ops-indexer, frontend must include
NEXT_PUBLIC_USER_OPS_INDEXER_URL - ALWAYS check the chart CHANGELOG.md before upgrading chart versions
Helm Deployment Safety
- Template before deploying:
helm template <release> blockscout-stack --version <ver> -n <ns> -f values.yaml - Default image tags for backend, frontend, and user-ops-indexer are
latest— ALWAYS override with pinned tags - Backend
terminationGracePeriodSecondsdefaults to 300 — do not reduce below 120 (indexer needs graceful shutdown for DB consistency) - Backend liveness probe
initialDelaySecondsis 100, readiness is 60 — these are intentionally high due to Elixir startup time. Do not reduce without testing. - Verify rendered manifests for
APPLICATION_MODE,DISABLE_INDEXER, andRELEASE_COOKIEvalues - Resource defaults: backend 1-2 CPU / 2-4Gi, frontend 250-500m / 256Mi-1Gi, stats 250m / 512Mi
Database Operations
- Migrations run automatically via init container:
Elixir.Explorer.ReleaseTasks.create_and_migrate() - ALWAYS back up the database before upgrades — Elixir migrations are forward-only, no automatic rollback
- When
separateApi.enabled, migrations run as a Helm pre-install/pre-upgrade Job instead of init container - Failed migration Jobs persist for debugging (
hook-delete-policy: hook-succeeded) — checkkubectl get jobs -n <ns>after upgrade failures - Stats, user-ops-indexer, and other Rust services use separate databases — verify
STATS__DB_URLandUSER_OPS_INDEXER__DATABASE__CONNECT__URLpoint to different instances - PostgreSQL 12-17 supported
Separate API/Indexer Pattern
- Enable with
blockscout.separateApi.enabled: true— splits into API (APPLICATION_MODE=api) and Indexer (APPLICATION_MODE=indexer) Deployments - Requires backend >= 6.6.0 (chart >= 1.6.0)
- Indexer image uses
-indexertag suffix — when pinning tags, confirm both<tag>and<tag>-indexerexist - Distributed Elixir activates automatically:
RELEASE_DISTRIBUTION=name, inet_dist ports 9138-9139 - RELEASE_COOKIE defaults to
secret— ALWAYS change in production (it is the Erlang distribution authentication cookie) - Only ONE indexer replica is supported — do not set
blockscout.replicaCount > 1on the indexer - API replicas scale independently via
separateApi.replicaCount
Microservice Configuration
- Rust services use double-underscore env var pattern:
{SERVICE}__{SECTION}__{KEY}=value - Common ports: HTTP 8050, gRPC 8051, metrics 6060. Exception: sig-provider uses port 8043.
- Health endpoints: backend
/api/health/livenessand/api/health/readiness, frontend/api/healthz, Rust services use gRPC health check protocol - Stats requires
STATS__BLOCKSCOUT_API_URL— auto-set by chart when ingress exists, must be set manually otherwise - Stats conditional start: waits for backend indexing to reach
blocks_ratio >= 0.98before computing charts
Monitoring & Health
- Built-in Prometheus:
config.prometheus.enabled: truecreates ServiceMonitor for backend and stats - Blackbox exporter probe:
config.prometheus.blackbox.enabled: trueprobes/api/healthexternally - PrometheusRule alerts:
BlockscoutNoNewBatchesfires when latest batch timestamp exceedsbatchTimeMultiplier * batch_average_time - Default
healthyBlockPeriod: 300(5 minutes) — adjust per network's expected block time - Metrics ingress whitelist (
config.prometheus.ingressWhitelist) restricts/metricsto private subnets — do not disable in production - When running separateApi: Prometheus rules target the indexer service specifically
Secret Management
Four methods, in order of preference:
envFrom+secretRef— reference existing K8s Secret (preferred, lifecycle managed externally)extraEnv+secretKeyRef— reference individual keys from existing SecretsenvFromSecret— chart creates a Secret from inline values (recoverable viahelm get values)env— plain env vars (visible in rendered manifests)
DATABASE_URL, NFT storage credentials, and RELEASE_COOKIE should ALWAYS use method 1 or 2.
Upgrade & Rollback
- Rollback:
helm rollback <release> <revision> -n <ns>— checkhelm historyfor last good revision - Rolling back the Helm release does NOT roll back database schema — older app versions may be incompatible with newer schema
- For major version downgrades, restore from database backup
- NEVER use
--reuse-valuesacross blockscout-stack chart version bumps — new required env vars will be missed - Breaking change gates: v4.0.0 (distributed Elixir + NFT), v3.0.0 (GHCR registry + API-only removed)
Troubleshooting
- Backend not starting: check init container / migration Job logs first. Elixir startup is slow (60-100s) — do not restart prematurely.
CrashLoopBackOff: check DATABASE_URL connectivity, missing required env vars, or schema version mismatch- Stats not populating: verify
STATS__BLOCKSCOUT_API_URLis reachable from stats pod, check conditional start thresholds - Frontend 502: verify
NEXT_PUBLIC_API_HOSTpoints to the backend, verify backend readiness probe is passing - Distributed Elixir issues (separateApi): verify inter-pod connectivity on ports 9138-9139, verify RELEASE_COOKIE matches, check NetworkPolicy
Anti-Patterns to Flag
- Deploying with default image tags (
latest) for backend, frontend, or user-ops-indexer - Leaving RELEASE_COOKIE as
secretin production (Erlang distribution authentication bypass) - Using
envFromSecretfor DATABASE_URL or credentials (recoverable viahelm get values) - Upgrading chart major version without checking CHANGELOG.md
- Reducing backend liveness probe
initialDelaySecondsbelow 60 (Elixir startup is slow — premature restarts) - Enabling
separateApiwithout verifying backend image >= 6.6.0 - Missing
STATS__BLOCKSCOUT_API_URLwhen stats are enabled without ingress (stats silently fails) - Upgrading chart without database backup (migrations are forward-only)
- Setting
blockscout.replicaCount > 1on the indexer (only one indexer replica supported) helm upgrade --reuse-valuesacross chart version bumps (misses new required env vars)- Pinning backend tag without confirming
<tag>-indexervariant exists when separateApi is enabled - Disabling
config.prometheus.ingressWhitelistin production (exposes metrics publicly) - Running database-heavy operations (reindexing, stats force-update) without increasing resource limits