Self-hosted service
GreenmaskIO/greenmask avatar
GreenmaskIO/greenmask

Greenmask sits between pg_dump and your staging database

Database anonymization and test data management

1,789 stars78 forksGoApache-2.0

At a glance

What is it?
Greenmask is a Go utility that dumps a PostgreSQL database, transforms the data on the way out and writes a logical backup that pg_restore can read, so masked data never touches disk untransformed. PostgreSQL is production ready, MySQL is beta, and transformation behaviour lives in a config file plus optional external commands.
Who is it for?
Adopt Greenmask if your staging and analytics databases are built from production dumps and you need referentially intact subsets with masked personal data, since that is exactly its pipeline. Do not plan a MySQL rollout on it yet, as the README marks that database work in progress at beta.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

It is a dump proxy, not a client library

The position Greenmask takes is architectural rather than cosmetic. It operates as a logical dump proxy: it reads from the source database, applies transformations in flight, and writes a logical backup. Because the output is a standard logical dump, it is compatible with pg_restore and with mysqldump conventions, so nothing downstream needs to learn a new format.

That has one consequence worth being clear about. Data never lands on disk in its original form, which is the property you want when the intermediate dump would otherwise be a second copy of your production personal data. It also means Greenmask is a batch tool tied to a dump and restore cycle, not something that sits inside an application path.

The tool is stateless, ships as a single binary, and runs cross platform. PostgreSQL is described as fully supported and production ready; MySQL is marked work in progress at beta, with the tracking issue linked from the README.

Subsetting that keeps foreign keys intact

The use case the project leads with is a smaller development database that still makes sense. Greenmask's subsetting produces referentially intact databases, and the feature list calls out cyclic and polymorphic references specifically.

Those two cases are where naive sampling breaks. A cyclic reference means a row participates in a loop of foreign keys, so deleting rows naively leaves either dangling references or an empty table. A polymorphic reference means one column points at different target tables depending on another column, so a tool that assumes a single target table gets it wrong. Supporting both is a claim worth testing against your own schema rather than taking on trust.

The payoff for a development team is that a developer gets a database with the same shape as production rather than a hand-built schema with guessed contents.

Hashing is deterministic, which is what makes it usable

The masking primitive is a hash engine, and the README stresses that it is deterministic: the same input always produces the same output.

That property is what separates this from a random faker. With a random value, a foreign key column masked independently would point at a value that no longer exists in the referenced table, and a masked email in an orders table would not match the same customer row elsewhere. With a deterministic hash of the original value, the same input masks to the same output everywhere in the database, so relationships survive masking.

That is also what makes anonymized dumps comparable across refreshes, since a value does not change between two runs when the source has not changed. A secondary property follows: a hash of a low cardinality column, such as a country code, can be guessed or brute forced from a small value space, so treat the engine as pseudonymisation and decide per column whether an attacker could reverse it.

Dynamic parameters and transformation conditions

Two features exist for the case where independent per column transformation breaks a business rule.

Dynamic parameters let a transformer read other columns of the same row. The example given is maintaining created_at less than updated_at, which a random or purely derived timestamp transformation would break. A transformer can now base its output on the values already present in that row.

Transformation conditions go one level up in scope, applying a transformation only when criteria are met, at either table scope or transformer scope. That is how you mask one column but only inside rows selected by another condition, for example transforming free text fields only in rows where a status column marks them as sensitive.

Together they cover most of what makes masking a database hard: keeping derived values consistent inside a row and keeping the rules selective rather than blanket.

Inheritance removes the repetitive half of the config

Transformation inheritance is described as eliminating redundancy by automatically applying transformations to partitioned tables and to foreign key references.

The foreign key half is the more valuable of the two, and it follows from the determinism argument above. If a primary key column is masked, every column that references it must be masked the same way, and configuring that by hand across a schema with many tables is exactly the kind of work that gets done once and then forgotten when a table is added. Automating it removes a class of broken dump where the masked child rows no longer join.

The partitioned table case is the mirror image: a transformation declared on a parent should not have to be repeated on every partition.

The configuration is a YAML file, and config.yml.example sits at the repository root, which is the fastest way to see the real shape of the schema rather than guessing from documentation.

Custom transformations run as external commands

The extension story is the CMD transformer, which implements a domain specific transformation in any programming language. The README documents predefined templates as a starting point for writing your own.

This is the right shape for a masking tool, since the transformations that matter are organisation specific: a custom national identifier format, a credit card test range, a name that has to stay internally consistent across two tables with different rules. Anything expressible as a command taking a row in and returning a row out can be plugged in.

The cost is the boundary you are introducing. An external process per row is a performance and a reliability concern on large tables, and a crash mid dump leaves you with a partial file. Built in transformers are the path with fewer surprises; reach for CMD only where the standard set genuinely cannot express the rule.

Storage backends and the sandbox

Backups do not have to land on a local disk. Greenmask supports local directories and S3 compatible storage, named in the README as AWS S3, MinIO and GCS among others, which is what makes it usable where a dump is too large for a developer's laptop or where backups are expected to be encrypted at rest by the storage layer.

The quickest way to see it work is the sandbox, which ships with a sample database and pre-configured transformations:

bash
git clone [email protected]:GreenmaskIO/greenmask.git && cd greenmask
docker-compose run greenmask

There is more than one compose file at the root, and the names describe the deployment situations rather than features: docker-compose.yml for a local run, docker-compose-integration.yml for integration testing, docker-compose-ssh.yml for access over SSH and docker-compose-azure.yml for Azure.

An install.sh is also present for people who would rather not build the binary, and a Makefile covers the usual Go targets.

Licence, maintenance and the gaps

Greenmask is Apache 2.0, with SECURITY.md at the root for responsible disclosure and.golangci.yml showing the project lints with golangci-lint rather than relying on gofmt alone.

Development is current. The last push was on 2026-10-10, and releases v0.2.23, v0.2.24 and v0.2.25 shipped between August and September 2026.

The real gaps are stated rather than hidden. MySQL is beta. There is no mention of differential privacy despite the topic, so the anonymization is pseudonymisation with hashes and transforms rather than a formal privacy guarantee, which matters if a compliance regime asks for one. And the tool depends on the native driver for encoding and decoding, which the README lists as a type safety feature but which also means behaviour follows the driver's handling of the less common types in your schema.

Editorial conclusion

Adopt Greenmask if your staging and analytics databases are built from production dumps and you need referentially intact subsets with masked personal data, since that is exactly its pipeline. Do not plan a MySQL rollout on it yet, as the README marks that database work in progress at beta. Verify first that the transformations you rely on are the built in hash and standard transformers rather than a custom command, and confirm your dump is readable by the pg_restore version you actually use.

Frequently asked questions

Which databases does Greenmask support?

PostgreSQL is fully supported and described as production ready. MySQL is marked work in progress at beta, with the tracking issue linked from the README.

How does Greenmask anonymize data?

It uses deterministic hash functions and other built in transformers while dumping, so the same input always produces the same output. That keeps foreign key relationships consistent across tables and makes two runs of the same source comparable.

Can Greenmask create smaller development databases?

Yes. Its database subsetting feature produces smaller, referentially intact databases, with support for cyclic and polymorphic references, which are the cases where naive sampling leaves broken foreign keys.

How do I try Greenmask quickly?

Clone the repository, cd into it and run docker-compose run greenmask, which starts the sandbox with a sample database and pre-configured transformations. The documentation site also offers a playground.

Official sources

  1. GreenmaskIO/greenmask on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/greenmaskio-greenmask.svg)](https://hysenlabs.com/projects/greenmaskio-greenmask)

Was this useful?