ngx-local-vault
July 4, 2026 · View on GitHub
Reactive, encrypted browser storage for Angular — built on Signals, under 2KB gzipped, zero runtime dependencies.
Also available for: React (npm · demo) · Vue (npm · demo)
Most storage wrappers give you a getter/setter pair and leave persistence, encryption, and expiry as an exercise for the consumer. ngx-local-vault collapses all three into a single WritableSignal: read it like any other signal, write it like any other signal, and the library takes care of encrypting the payload, syncing it to localStorage or sessionStorage, expiring it on a TTL, and staying inert during SSR.
- Signals-native —
watchSignal()returns a realWritableSignal<T>, no wrapper API to learn - Encrypted at rest — payloads are obfuscated before they ever touch the browser's storage
- TTL built in — pass
expiresIn: '1m'and the entry self-destructs, in-tab, without a reload - SSR-safe — guarded by
PLATFORM_ID, becomes a no-op persistence layer on the server - Zero dependencies —
@angular/coreand@angular/commonas peers, nothing else
Install
npm i ngx-local-vault
Supports Angular 17, 18, 19, and 20.
Configure
import { ApplicationConfig } from '@angular/core';
import { provideVault } from 'ngx-local-vault';
export const appConfig: ApplicationConfig = {
providers: [
provideVault({ prefix: 'app_', encryptionKey: 'change-me', driver: 'local' })
]
};
Use
import { inject } from '@angular/core';
import { VaultService } from 'ngx-local-vault';
const vault = inject(VaultService);
const theme = vault.watchSignal<'light' | 'dark'>('theme', 'light');
theme.set('dark');
theme();
const session = vault.watchSignal<string | null>('session-token', null, { expiresIn: '15m' });
session.set('jwt-goes-here');
expiresIn accepts ms, s, m, h, or d suffixes — '500ms', '30s', '15m', '2h', '1d'.
Demo
Live: https://ysndmr.github.io/ngx-local-vault/
projects/demo-app is a live showcase: a theme switcher backed by watchSignal(), and a TTL demo that saves a mock profile, shows the encrypted ciphertext sitting in localStorage next to the decrypted reactive value, and lets you watch it auto-delete after 60 seconds.
npm install
npm run build:lib
npm start
npm start serves demo-app; the library must be built first since the app imports ngx-local-vault from its built output (dist/ngx-local-vault), not the source directly — standard Angular library-workspace convention.
Publishing (maintainer)
-
Log in to npm once, locally:
npm login -
Build the library — this also strips
tslibfrom the publisheddependencies(ng-packagr adds it back on every build;scripts/patch-lib-package.mjsremoves it) so the zero-dependency badge stays honest:npm run build:lib -
Dry-run the publish before it's live:
cd dist/ngx-local-vault npm publish --dry-run -
If the file list and
package.jsonlook right, publish for real:npm publish --access public
CI (.github/workflows/publish.yml) does this automatically on every push to main: it builds the library and the demo app, deploys the demo to GitHub Pages, and publishes to npm if an NPM_TOKEN secret is configured on the repository (Settings → Secrets and variables → Actions). No token, no publish step — the Pages deploy still runs.
License
MIT