Encryption and privacy
Standard, end-to-end, and hybrid privacy modes with key management and rotation
npayload provides three privacy modes that control how message payloads are handled. You choose a privacy mode when creating a channel, and it applies to every message published to that channel.
Privacy modes overview
| Mode | Payload | Metadata | npayload can read payload | Use case |
|---|---|---|---|---|
| Standard | Stored as-is | Visible | Yes | General messaging, event streaming |
| E2E | Encrypted client-side | Visible | No | Medical records, financial data, PII |
| Hybrid | Encrypted client-side | Visible | No (payload only) | Compliance with metadata-based routing |
Standard mode
The default mode. npayload stores and delivers payloads as-is. This enables features like payload indexing, content-based routing, and server-side filtering.
const channel = await npayload.channels.create({
name: 'order-events',
type: 'standard',
privacy: 'standard',
});
await npayload.messages.publish('order-events', {
payload: { event: 'order.created', total: 59.98 },
});npayload encrypts all data at rest and in transit using TLS 1.3. Standard mode means npayload's infrastructure can read the payload for processing purposes.
End-to-end (E2E) mode
In E2E mode, payloads are encrypted on the client before they leave your application. npayload transports and stores the encrypted blob but cannot decrypt it. Only consumers with the correct decryption key can read the payload.
const channel = await npayload.channels.create({
name: 'medical-records',
type: 'standard',
privacy: 'e2e',
});Publishing with E2E encryption
The SDK handles encryption automatically when you provide an encryption key.
import { NPayloadAuth, NPayloadClient } from '@npayload/node';
const npayload = new NPayloadClient({
auth,
encryption: {
key: process.env.NPAYLOAD_ENCRYPTION_KEY!,
},
});
// Payload is encrypted before leaving your application
await npayload.messages.publish('medical-records', {
payload: {
patientId: 'pat_12345',
diagnosis: 'Routine checkup, all clear',
},
});Consuming E2E messages
Consumers must be configured with the same encryption key.
const npayload = new NPayloadClient({
auth,
encryption: {
key: process.env.NPAYLOAD_ENCRYPTION_KEY!,
},
});
const messages = await npayload.streams.read('medical-records', {
position: 'beginning',
limit: 10,
});
// Payload is decrypted automatically
for (const msg of messages.items) {
console.log(msg.payload.patientId); // "pat_12345"
}What npayload sees in E2E mode
| Field | Visible to npayload |
|---|---|
| Channel name | Yes |
| Message GID | Yes |
| Timestamp | Yes |
| Routing key | Yes |
| Metadata | Yes |
| Payload | No (encrypted blob) |
In E2E mode, npayload cannot inspect payloads. Features that depend on payload content (such as content-based routing or server-side filtering) are not available. Use routing keys and metadata for filtering instead.
Hybrid mode
Hybrid mode encrypts the payload while keeping metadata visible. This is useful when you need npayload to route and filter based on metadata, but the payload itself contains sensitive data.
const channel = await npayload.channels.create({
name: 'financial-events',
type: 'standard',
privacy: 'hybrid',
});
await npayload.messages.publish('financial-events', {
payload: {
accountId: 'acc_789',
amount: 15000.00,
currency: 'USD',
},
metadata: {
eventType: 'wire.transfer',
region: 'us-east',
riskLevel: 'high',
},
routingKey: 'wire.transfer.us-east',
});In hybrid mode:
metadataandroutingKeyare stored in plaintext. npayload can use them for routing and filteringpayloadis encrypted client-side. npayload stores it as an encrypted blob
When to use each mode
Choose standard when:
- Payload data is not sensitive (event notifications, system metrics, public data)
- You want full npayload features including payload indexing and content-based routing
- Your compliance requirements are satisfied by npayload's at-rest and in-transit encryption
Choose E2E when:
- Payloads contain highly sensitive data (medical records, financial PII, legal documents)
- Regulatory requirements mandate that no intermediary can access payload data
- You are willing to handle key distribution between publishers and consumers
Choose hybrid when:
- Payloads are sensitive but you need metadata-based routing and filtering
- You want npayload to handle delivery logic based on event type, region, or priority while keeping the actual data encrypted
- Common in financial services, healthcare event buses, and multi-tenant SaaS platforms
Key management
Generating a key
The SDK includes a utility for generating encryption keys.
import { generateEncryptionKey } from '@npayload/node';
const key = generateEncryptionKey();
console.log(key); // Base64-encoded 256-bit keyStore this key securely in your secret vault. Both publishers and consumers need the same key for a given channel.
Key rotation
To rotate keys without downtime:
- Add the new key to your consumers first (configure them to try both keys)
- Update publishers to use the new key
- After the channel's retention period has elapsed, remove the old key from consumers
const npayload = new NPayloadClient({
auth,
encryption: {
key: process.env.NPAYLOAD_ENCRYPTION_KEY_NEW!,
previousKeys: [process.env.NPAYLOAD_ENCRYPTION_KEY_OLD!],
},
});When previousKeys is set, the SDK tries the primary key first. If decryption fails, it tries each previous key in order. This allows consumers to read both old and new messages during the rotation window.
Key rotation is transparent to npayload. Since the encrypted payload is opaque, npayload does not need to know about your key changes.
Encryption details
| Property | Value |
|---|---|
| Algorithm | AES-256-GCM |
| Key size | 256 bits |
| IV | Unique per message (generated by the SDK) |
| Authentication tag | Included in the encrypted blob |
| Key derivation | HKDF-SHA256 from your base key |
Best practices
- Choose the privacy mode at channel creation time. It cannot be changed later
- Never transmit encryption keys over insecure channels. Use your platform's secret management
- Rotate keys on a regular schedule (quarterly is a common baseline)
- In E2E mode, use metadata and routing keys for any server-side filtering you need, since payloads are opaque to npayload
- Test key rotation in a staging environment before applying to production
Next steps
Was this page helpful?