Dartvel, home
Docs
Features
Studio
Cloud
Compared

Search the site

GitHub
pub.dev

GETTING STARTED

Getting started
Existing Flutter apps
Existing Native apps
Run on your phone

APP

UI and styling
Routing
State
Accessibility
Keyboard shortcuts
Localization
Devices and desktop
Native device access
Media, 3D and XR

DATA

Data models
Forms
Search
Sync and offline
Import and export
Change capture
Database
Cache
File storage
Images
Privacy and erasure

BACKEND

Backend functions
Auth and sessions
Authorization
Queues and jobs
Workers and memory
Notifications and mail
Outbound HTTP
AI
Webhooks
GraphQL and OpenAPI
API keys and OAuth
Multi-tenancy
Billing and commerce
Modules

OPERATIONS

Edge security
Secrets and environments
Monitoring
Releases

SHIPPING

Build targets
Telegram Mini Apps
Static web hosting
Servers and deploying

REFERENCE

Testing
CLI reference
Coding agents

DATA

Cache

DV.Cache is four calls, get, set, has and delete, from a page or a backend function.

Everything else is an option on those four: get computes a missing value, set takes tags, and delete drops a key, a tag or everything.

ON THIS PAGE

Get, set, has and delete

Compute a value on a miss

Drop a group of keys by tag

Serve stale data while it refreshes

Choose where the cache lives

Run work once

Manage a database cache from the CLI

Public HTML is cached automatically

Status

Get, set, has and delete

await DV.Cache.set('greeting', 'hello', ttl: const Duration(hours: 1));
final String? greeting = await DV.Cache.get<String>('greeting');
final bool cached = await DV.Cache.has('greeting');
await DV.Cache.delete('greeting');

Copy code to clipboard

ttl is named. Without one an entry stays until it is deleted.

get returns null for a missing key, an expired one, or a value of another type.

A backend function uses the same calls, with DV from package:dartvel_core/dv.dart.

Compute a value on a miss

Future<List<String>?> productNames() => DV.Cache.get<List<String>>(
      'products:names',
      compute: fetchProductNames, // runs only when the key is missing or expired
      ttl: const Duration(minutes: 10),
      tags: <String>['products'],
    );

Copy code to clipboard

The compute runs only on a miss. Callers that ask for the same key at once share one compute.

A compute that throws stores nothing.

ttl, tags and staleFor apply to what the compute stores. Passing one to get without a compute is an error.

Drop a group of keys by tag

await DV.Cache.set('home:featured', <String>['Starter kit'],
    tags: <String>['products', 'home']);
await DV.Cache.delete(const DVCacheTag('products')); // every key tagged products
await DV.Cache.delete(DVCache.all); // every key

Copy code to clipboard

set and get take tags. delete(DVCacheTag(...)) removes every key with that tag, and delete(DVCache.all) removes every key.

delete takes one argument: a String key, a DVCacheTag or DVCache.all. Anything else is an error, never a guess.

Tags are kept in each server's memory. Deleting a tag drops the keys this server has tagged.

Serve stale data while it refreshes

final List<String>? names = await DV.Cache.get<List<String>>(
  'products:names',
  compute: fetchProductNames,
  ttl: const Duration(minutes: 1),
  staleFor: const Duration(minutes: 10),
);

Copy code to clipboard

After ttl and for staleFor more, callers get the old value at once while one compute refreshes it. After both, they wait for a new value. staleFor needs a ttl.

Choose where the cache lives

# pubspec.yaml
dartvel:
  cache:
    store: redis        # memory (default), database, redis or memcached
    url: ${REDIS_URL}   # read from the environment when the server starts
    prefix: "shop:"

Copy code to clipboard

memory

Keeps entries in: The server process. The default

database

Keeps entries in: The database in DATABASE_URL, table dartvel_cache. Change it with table:

redis

Keeps entries in: Redis or Valkey, at url

memcached

Keeps entries in: Memcached, at url

url reads an environment variable, such as ${REDIS_URL}. The build refuses a password written into pubspec.yaml.

prefix starts every key, so two applications can share one server. The default is dartvel:.

The server refuses to start when it cannot reach the store.

On a device, memory is the default store. The store in pubspec.yaml applies only to the server.

A device can switch store in code with withAdapter, below. Sharing a cache with the server is planned.

Keys are prefixed with the tenant unless it is the default one.

pubspec.yaml sets the store DV.Cache uses by default. DV.Cache.withAdapter switches to another store in code, with the same four calls:

final DVCacheView sessions = DV.Cache.withAdapter(
  await DVRedisCacheAdapter.connect(DV.Secrets.get('SESSIONS_REDIS_URL')),
);
await sessions.set('visitor:42', 'signed in', ttl: const Duration(hours: 8));
final bool active = await sessions.has('visitor:42');

Copy code to clipboard

Every call goes to the adapter you pass, never to the default store.

The adapters are DVMemoryCacheAdapter, DVDatabaseCacheAdapter, DVRedisCacheAdapter, DVMemcachedCacheAdapter and DVDistributedCacheAdapter.

Tags and the shared compute are kept per adapter, so deleting a tag on one store leaves the others alone.

Run work once

For work only one server should do, such as a monthly report, declare a schedule. Each occurrence is claimed once across cron processes, and a process does not start a schedule again while its last run is still going. Unique jobs are not built yet.

Manage a database cache from the CLI

dartvel cache purge --database dartvel.db   # drop expired entries
dartvel cache clear --database dartvel.db

Copy code to clipboard

Public HTML is cached automatically

dartvel build web-server

Copy code to clipboard

Since 0.11.5, safe public GET pages with compiled content reuse their rendered HTML after the first request. This is automatic and separate from the four DV.Cache calls.

Cookies, authorization, guarded routes and runtime page data bypass the document cache. Studio saves and publishes and successful OTA updates purge it. ETags allow revalidation with a 304 response. Use cache: false on a DVRoute in route configuration to opt out.

Planned

Invalidation across server processes is not yet implemented. Each process has its own bounded cache.

Status

Partial

Spec section: Cache

Planned work and implementation limits

No model query cache, and no caching a backend function by annotation.

Model writes do not drop tags yet. Call delete(DVCacheTag(...)) yourself.

A device cannot share the server's cache yet. The plan is an adapter that calls the server, with every call checked against a policy and scoped to the tenant.

Several Redis or Memcached nodes are not a store pubspec.yaml can name yet. Pass a DVDistributedCacheAdapter to withAdapter instead.

PREVIOUS Database SQLite, Postgres, MySQL and migrations
NEXT File storage Files on local disk, S3, GCS or Azure
GitHub
pub.dev
npm
Acknowledgements
Privacy
Terms

FSL-1.1-MIT licensed. Built with Dartvel.

Dartvel is made by

SigmaDev Digital

To the bottom