Queryable Encryption
Queryable Encryption lets your application query encrypted data without exposing the underlying values to the database. Fields remain encrypted everywhere outside your application, including when they are stored and queried on the cluster. Your application encrypts values before sending them to MongoDB, and decrypts them when they are returned. This allows you to search encrypted fields while keeping sensitive data protected.
How it compares with other encryption mechanisms
Each mechanism protects a different stage of the data's life.
| Mechanism | Protects data | Server sees plaintext |
|---|---|---|
| SSL/TLS | In transit | Yes |
| Disk encryption (TDE) | At rest | Yes, the server decrypts it to work with it |
| Queryable Encryption | In transit, at rest, and in use | No |
The three are complementary, not alternatives. Only the last column changes what someone with read access to the database can see.
How it works
Your application code does not change shape. You write {ssn: "123-45-6789"} and you read it back the same way, while the driver and a library called crypt_shared encrypt on the way out and decrypt on the way in.

The middle row is what makes this more than ordinary client-side encryption. The driver encrypts the search filter too, so the server matches ciphertext against ciphertext and returns the right documents without learning what you searched for.
Which queries still work
Matching only works for the query type you declare when you create the collection, and that choice is permanent for the life of the collection.
| Query type | Use for | Status |
|---|---|---|
equality | $eq, $in, $ne | Production-ready from MongoDB 7.0 |
range | $lt, $lte, $gt, $gte | Production-ready from MongoDB 8.0 |
prefix, suffix, substring | Prefix, suffix, and substring search | Production-ready from MongoDB 9.0 |
none | Encrypt a field without querying it | Always available |
Version 8.0.20 gives you equality and range, while 7.0.30 gives you equality only. Version 6.0.27 cannot be used at all, because MongoDB 6.0 shipped Queryable Encryption as a public preview that is no longer supported.
Limitations to plan around
Encrypting a field narrows what you can do with it. Read this list against your application's real queries before you settle on a schema.
The first limitation shapes everything else. You can enable Queryable Encryption only on a new, empty collection, and you cannot change which fields are encrypted afterwards. Getting it wrong means creating a new collection and migrating the data.
The rest apply to the encrypted fields themselves.
- A collection cannot use Queryable Encryption and CSFLE at the same time.
collationis not supported.updateManyanddeleteManyare not supported, andbulkWriteis limited to a single namespace.- Updates to an encrypted field accept
$setand$unsetonly, not$incor$push. findOneAndUpdateandfindOneAndReplacemust return the document as it was before the change (returnDocument: before) and cannot use a projection.- Querying an encrypted field with
null, with a regular expression, or against another encrypted field fails. - In aggregation,
$outand$mergeare unavailable, and$groupworks on unencrypted fields only. distinctis unavailable.- Drop the collection with a client that has Queryable Encryption enabled, otherwise the metadata collections are left behind.
The full list is in MongoDB's Supported Operations for Queryable Encryption.
Setup steps
The sequence is the same in every language, and the two pages that follow work through it line by line.

Create the master key
For a trial this is a local file holding 96 random bytes, read once when the application starts. Production replaces it with a KMS (AWS, Azure, GCP, or KMIP).
Declare the fields
Each encrypted field needs a path, a bsonType, and a queryType. The queryType decides which operators still work on that field, and it cannot be changed once the collection exists.
Create the collection
One call does three things. The driver generates a Data Encryption Key per field, the server creates the collection, and the server adds the metadata collections enxcol_.<COLLECTION>.esc and enxcol_.<COLLECTION>.ecoc next to it. The collection must not already exist.
Build the encrypting client
This is a second client, separate from the plain one that created the collection. It takes the field map returned by step 3, which by now carries the key IDs the driver generated. Steps 3 and 4 have to happen in that order, because the field map only gains those key IDs once the collection exists.
Read and write
From here the collection behaves like any other. The driver encrypts the declared fields before they leave the process and decrypts them when the documents come back.
Data encrypted with a lost master key is unrecoverable. Back the key file up somewhere separate from the database, and move to a KMS before you put real data behind it.
Checking that it works
Once the script runs, the same document looks completely different depending on which client reads it.
- Through the encrypted client,
ssnreads back as plaintext. - Through an ordinary client, or
mongoshwithout the key,ssnisBinDatasubtype 6, and the document carries an extra__safeContent__field. - Searching for the plaintext value through an ordinary client returns nothing at all.
Common errors
The table maps each message to what causes it.
| Error | Cause and fix |
|---|---|
mongo_crypt_v1.so not found | The path is wrong, or crypt_shared is not installed on the application host |
A crypt_shared version error | crypt_shared must be the same version as the server or newer |
Multi-document updates are not allowed with Queryable Encryption | The code calls updateMany. Use updateOne |
Invalid match expression operator on encrypted field | The operator is not supported for that field's query type, such as a regex or $gt on an equality field |
findAndModify with encryption only supports new: false | The call uses returnDocument: after. Change it to before |
| The collection already exists | Queryable Encryption needs an empty new collection. Drop it with an encryption-enabled client first |
| Authentication fails on connect | The password contains characters that were not URL-encoded |
Recommendations for production
The examples use a local key file to keep the first run simple. Change these before real data goes in.
- Use a KMS (AWS, Azure, GCP, or KMIP) instead of a local key. A local key sits in a file, so whoever obtains that file can decrypt everything it protects.
- Keep passwords out of source code. Read them from environment variables or a secret manager.
- Encrypt only the fields that genuinely need it. Each encrypted field costs query flexibility and storage, through the
enxcol_.*metadata collections and__safeContent__. - Decide which fields need queries before you create the collection, since that choice cannot be revised later.
- Test the application's real queries against the supported operator list before you deploy, not after.
References
The pages below are MongoDB's own documentation, and they go further than this guide does.
- Queryable Encryption is the feature's home page in the MongoDB manual.
- Compatibility lists the server versions, drivers, editions, and cluster topologies that support it.
- Limitations carries the full restriction list, including the ones this page does not repeat.
- Supported operations covers every command and operator that works on an encrypted field.
- Quick start is MongoDB's own walkthrough, available in several languages.
- Automatic Encryption Shared Library explains how to obtain and configure
crypt_shared.