Last updated on 5th August 2026

SOPS: Encrypt Secrets in Config Files You Can Commit

Committing secrets to Git is a well-known mistake — but keeping them entirely out of the repository has its own cost: now there's a separate system of record for configuration, and staying in sync across environments and teammates becomes its own chore. SOPS (Secrets OPerationS) offers a middle path: encrypt the secret values inside your config files, commit the encrypted files, and decrypt them only where and when they're needed.

The clever part is what SOPS doesn't encrypt. In a YAML or JSON file, it leaves the keys and structure readable and encrypts only the values. Your database_url: line still says database_url: in Git — just with an encrypted value — so diffs stay meaningful and reviewers can see what changed without seeing the secret itself.

SOPS vs a .env encryptor

If you only deal with flat .env files and want the simplest possible workflow, a dedicated tool like dotenvx is the lighter choice — see the dotenvx guide to encrypting .env files. SOPS earns its place when you need more: structured files (YAML, JSON, INI), multiple key backends (age, PGP, and cloud KMS from AWS, GCP, or Azure), and fine-grained rules for which files and which keys get encrypted. It's the more ops-grade option, common in Kubernetes and infrastructure-as-code setups.

Installing SOPS and age

SOPS supports several encryption backends; age is the simplest to start with (modern, no GPG keyring to manage):

# macOS / Linux
brew install sops age

Generate a key

Create an age key pair. The public key encrypts; the private key decrypts.

age-keygen -o key.txt
# Public key: age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8j

Keep key.txt (the private key) out of version control, and store it wherever you keep secrets — a password manager locally, and your deployment platform's secret storage for production.

Configure which files to encrypt

Add a .sops.yaml at your repo root to tell SOPS which files to encrypt and with which key:

creation_rules:
  - path_regex: secrets/.*\.yaml$
    age: age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8j

Encrypt a file

Write your secrets as normal YAML:

# secrets/production.yaml
database_url: postgres://user:password@db.internal/app
api_key: sk_live_abc123

Then encrypt it in place:

sops encrypt --in-place secrets/production.yaml

The file now keeps its structure but hides the values:

database_url: ENC[AES256_GCM,data:Xy9...,type:str]
api_key: ENC[AES256_GCM,data:Kp2...,type:str]
sops:
    age:
        - recipient: age1ql3z7...
          enc: |
            -----BEGIN AGE ENCRYPTED FILE-----
            ...

This encrypted file is safe to commit. To view or edit it later, sops secrets/production.yaml opens it decrypted in your editor and re-encrypts on save.

Use the secrets

Decrypt to stdout, or inject the values straight into a process as environment variables:

# decrypt to view
sops decrypt secrets/production.yaml

# run a command with the secrets loaded as env vars
sops exec-env secrets/production.yaml 'node server.js'

Decrypting at deploy time with DeployHQ

The deployment model mirrors any encrypt-in-Git workflow: the encrypted file travels with your code, and the key is what you protect. Store your age private key as a config file or environment value in DeployHQ rather than committing it, and decrypt during your build or release so plaintext secrets never touch the repository or your deployment logs.

Add the decryption step to your build pipeline — install SOPS, then run sops decrypt (or sops exec-env) with the key supplied from DeployHQ's configuration — and enable automatic deployments so every push ships the encrypted config and resolves it at deploy time. The encrypted file is the only secret artifact in your repository, and it's useless without the private key held separately in DeployHQ.

When to reach for SOPS

Choose SOPS when you have structured configuration, want to encrypt only the sensitive values while keeping readable diffs, or need cloud KMS-backed keys shared across a team and its CI. For a straightforward .env-only project, a lighter .env encryptor will get you there with less setup. Either way, the goal is the same: encrypted secrets in version control, decrypted only where they belong.

Ready to ship encrypted configuration to your own server? Create a free DeployHQ account and connect your repository in minutes.