ground-db and the caching-only offline layer for Meteor collections
GroundDB is a thin layer providing Meteor offline database and methods
At a glance
- What is it?
- GroundDB is a thin client-side layer that mirrors a Meteor Mongo collection into a local store so a subscribed app keeps working offline, backed by localforage rather than a hand-written storage adapter. The interesting part is what this version dropped, since it is caching only and no longer resumes method calls or synchronises across tabs, and the interesting constraint is that it still leans on Meteor's LocalCollection for its query surface.
- Who is it for?
- ground-db is a good fit for a Meteor application that needs its subscribed data readable while the network is gone, because it mirrors a live collection into a local store over localstorage, indexeddb or websql and gives you a keep mechanism to bound what is cached.
- Can I use it commercially?
- Yes. MIT 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 7 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What GroundDB does, and what this version gives up
GroundDB is described as a fast and thin layer providing Meteor offline database, with the tagline taking cloud data to the ground. The homepage is the Atmosphere package page at atmospherejs.com/ground/db, and the package is published as ground:db.
The core idea is straightforward. In a Meteor application, the client holds a Minimongo collection, a local in-memory store of the documents the server has published to the subscription. When the network drops, that store is fine as long as the app is running, but it starts empty on a fresh page load with no connection, and it is lost on reload. GroundDB persists that data to a real local store so a reload while offline gives the app its documents back.
What this version does not do is stated with unusual candour in the Features section. It is a caching only storage, meaning it does not support resuming of method calls or cross tab updates. The README frames this as a trade: it is faster and async, and in exchange those features are gone.
That is the single most important fact for an adopter. Offline support in the broad sense usually implies that a user can keep working and their changes are stored and sent later. GroundDB in this form gives you read access to cached data, not a write queue. A form submission made while offline is not held for replay, and a second browser tab does not see the first tab's writes.
The README points to notes about migration to GroundDB II for anyone who needs the fuller behaviour, so the previous version and its successor are both acknowledged parts of the story.
The storage layer: localforage with modifications
The storage backends are listed as localstorage, indexeddb and websql, with SQLite on Cordova shown as struck through in the README, meaning it is not currently supported.
The mechanism underneath is localforage, and the README is direct about the relationship: it is using localforage with some minor modifications, hopefully we can use localForage via npm in the future. That sentence carries a lot of information in a few words. localforage is the library that gives a uniform promise-based interface over the browser storage options, so the same code can use localstorage, indexeddb or websql depending on what is available. The package depends on it, but with local changes, which is what the future npm plan is about: moving to the published package rather than a forked copy.
The consequence for a maintainer is that this is not a case of depending on a stable upstream release. There is a fork in the dependency graph, with a maintainer-held set of modifications, and the intent is eventually to remove that fork. Anyone evaluating the package today is evaluating a modified copy of localforage, not localforage itself.
It also explains the platform list. localstorage has a small size limit and is synchronous, indexeddb is asynchronous and larger, and websql is a legacy API. Which one you get is decided by the library, not by you, which is convenient for the developer and inconvenient for anyone who needs to control the storage backend or reason about quota.
The choice is a good fit for a caching layer, where the data is a copy of server state and the size is bounded by what the user subscribes to. It would not be a good fit for an application that needs to control exactly where bytes land, for example to keep a local database file in a known directory.
Working with a Ground.Collection
A pure offline collection is created with a single constructor call:
foo = new Ground.Collection('test');And the README attaches an important constraint to it in italics: Ground.Collection is client-side only and depends on LocalCollection for now. Two facts in one sentence. It runs on the client only, so there is no server-side equivalent to instantiate, and it borrows its query implementation from Meteor's LocalCollection, which is why the collection behaves like a Mongo collection to your code.
The second fact is the one with a shelf life. LocalCollection is the Minimongo implementation, and Meteor 3 replaced the client-side data layer with a new driver that does not use Minimongo. Depending on LocalCollection for now is a statement that this package has not been ported to that model, which is a decision point for anyone starting a new application today rather than a detail for existing ones.
The data flow is a single method, observeSource, which takes a cursor from a Meteor Mongo collection and mirrors it into the Ground collection:
foo.observeSource(bar.find());And the mirror is stopped with stopObserver, which the README notes keeps all documents as is, so stopping the observer does not clear what has been cached.
That pairing, observeSource and stopObserver, is the whole lifecycle of the cache. Everything else in the API is about managing what stays in it.
Bounding the cache with keep, and clearing it
Because a caching layer with no eviction policy is a storage leak in a long-lived session, the API has a method for trimming the cache to match what is currently subscribed. The README introduces it as a way to clean up the storage so it matches the current subscription:
foo.keep(bar.find());The consequence, stated in italics, is that this will discard all documents not in the subscribed data. The same method handles limits, discarding all but a given number of documents:
foo.keep(bar.find({}, { limit: 30 }));And it accepts several cursors at once, which is the case worth understanding:
foo.keep(bar.find({ type: 'a' }, { limit: 30 }), bar.find({ type: 'b' }, { limit: 30 }));The README notes this keeps at max 60 documents, 30 of each type a and b. So the semantics are per-cursor limits rather than a single global budget, and the total is the sum.
That is a genuinely useful design, because a single limit applied to a heterogeneous collection either starves one type or floods the store, and the multi-cursor form lets you allocate. The subtlety is that keep is destructive. It is not a policy that runs automatically; it is a call you make, and the documents outside the cursors are gone from both memory and storage.
Clearing is the same shape, with the README noting it empties the in memory and the local storage:
foo.clear();The legacy shim, and why it exists
The README offers a near backwards compatible solution for applications that relied on the previous behaviour of caching a Mongo.Collection directly, and this section is the most instructive part of the documentation.
The GroundLegacy class extends Ground.Collection and takes a Mongo.Collection and an options object in its constructor. It throws an Error unless the argument is a Mongo.Collection, and it throws another Error unless options.cleanupLocalData is false. The reason for the second check is stated in the section heading: this class enforces a manual clean up.
The mechanics are then a matter of overriding. It stores the Mongo collection, observes the whole collection with this.observeSource(collection.find()), and then saves the original find and findOne methods on the collection as orgFind and orgFindOne before replacing collection.find and collection.findOne with versions that delegate to the Ground collection. The result is that code calling collection.find() transparently reads from the grounded data rather than from Minimongo.
The cleanup method removeLocalOnly then calls this.keep(this.mongoCollection.orgFind()), removing all documents not in the current subscription.
There is a lesson here about what this package is for. The legacy shim exists because the old version cached a Mongo collection and cleaned up automatically, and this version trades that automatic behaviour for speed. The shim reconstructs the old contract on top of the new one, and the two constructor errors are guard rails that stop you from using it in a configuration where the manual cleanup would never happen.
If you are maintaining an existing Meteor application that used the old ground db and wants to move, this class is the documented migration path, and the two error messages tell you exactly what the application code has to change.
Packaging, testing and the state of the project
The repository layout is small and tells you the project is a package rather than an application. There is a lib/ directory, a package.js, an EVENTS.md documenting events, a CHANGELOG.md, a .jshintrc, a .travis.yml, and two test files, groundDB.client.tests.js and groundDB.server.tests.js.
The package.json is where the packaging story is clearest. The name is db and the version is 0.0.0-semantic-release, because releases are automated by semantic-release rather than hand-numbered, and the release configuration lists semantic-release-meteor and @semantic-release/github as the verify conditions and the publish targets. The semantic-release-meteor plugin is what pushes a release to the Meteor package repository, and the GitHub plugin publishes the release and the changelog entry. The devDependencies are the release tooling: meteor-ci at 0.3.1, semantic-release at 25.0.2 and semantic-release-meteor.
The test script is worth noting: it echoes that tests are not implemented and exits zero. So the two test files in the root are not wired into a runner, and the package will report a passing test command regardless. That is a fact about the project, not a criticism, but it does mean you should not treat a green test run as evidence of anything.
The licence is MIT, with LICENSE.md at the root, and the repository is not archived. The last push was on 2026-10-16. The tagged releases are v2.1.0 and v2.1.1 from 2024-08-02 and v2.1.3 from 2026-08-07, so the version line is 2.1.x while the commits continue, which is the pattern of a package receiving fixes without a major release.
For events, the README points to a separate EVENTS.md document in the repository, which is where the event surface of the collection is documented rather than in the main readme.
Editorial conclusion
ground-db is a good fit for a Meteor application that needs its subscribed data readable while the network is gone, because it mirrors a live collection into a local store over localstorage, indexeddb or websql and gives you a keep mechanism to bound what is cached. It is a poor fit if you need offline writes to queue and replay, since this version is caching only and does not support resuming method calls or cross-tab updates, and a poor fit if you are on Meteor 3 with the new client-side driver, because the collection depends on LocalCollection for now. Before adopting, read the notes on migration to GroundDB II linked from the README, and check the keep API against your retention needs, since documents outside the cursors you pass are discarded rather than merely aged out.
Frequently asked questions
What is GroundDB and what does it do in a Meteor app?
GroundDB is a thin layer providing the Meteor offline database, taking cloud data to the ground by mirroring a subscribed collection into a local store so documents are available when the network is not.
Does GroundDB support offline writes and cross-tab updates?
No. The README states that this version is a caching only storage and does not support resuming of method calls or cross tab updates, in exchange for being faster and async.
Which local storage backends does GroundDB use?
The README lists localstorage, indexeddb and websql, with SQLite on Cordova shown as unsupported. It is built on localforage with some minor modifications, and the README says it is hoped localForage can be used via npm in the future.
How do I limit the amount of data GroundDB stores locally?
Call the keep method with a cursor or cursors from the Mongo collection. It discards all documents not in the subscribed data, and passing cursors with a limit keeps at most that many per cursor, so two cursors limited to 30 each keep at max 60 documents.
How do I install ground:db in a Meteor application?
The package is published on Atmosphere as ground:db, and the repository homepage is atmospherejs.com/ground/db. The README shows usage through the Ground.Collection constructor, for example `foo = new Ground.Collection('test')`.
What licence is ground-db released under?
MIT, with LICENSE.md at the repository root. The package uses semantic-release for versioning, so the package.json version is 0.0.0-semantic-release and the tagged releases are published separately, most recently v2.1.3.
Official sources
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.
[](https://hysenlabs.com/projects/meteor-community-packages-ground-db)Was this useful?