A simple and readable language for Firestore security rules, similar to Firebase Bolt.

License: MIT

Language: Haskell

Keywords: firebase, firebase-firestore, haskell, parser-combinators, typescript


A language and compiler for writing Firestore security rules. The compiler also generates TypeScript interfaces. The main idea is to be able to add idiomatic type validation to routes, as if they had strict type-checking. The language also has some nice features to elegantly express rules for certain situations, which otherwise would be too cumbersome to encode.

Mentioned in Awesome awesome-firebase


Questions, suggestions, etc.:!forum/fireward

Feature Highlights

  • Very fast compilation
  • Typed routes that convert to validation rule code.
  • const types that allow setting but prevent editing of individual fields
  • Tuple validation
  • Type unions


Method 0: NPM

npm install fireward

Method 1: Binary

Download a release binary and put it in your PATH.

Method 2: Compile Yourself

The project is easy to compile for most platforms, requires no knowledge of Haskell, and is completed in two simple steps:

  1. Download the Haskell Stack tool for your platform and put it somewhere, e.g. in your PATH.
  2. cd into the project directory and run stack install.

Afterwards, everything is automatic. Stack will download and install the compiler and dependencies and put the fireward executable into the path given by stack path --local-bin command. You may want to add that path to your PATH variable. The automatic download and build process will take about 5 minutes, if you have decent bandwidth and processing power.

Method 3: Use docker image

Install Docker, then use like this:

To generate Firestore rules

cat definitions.ward | docker run --rm -i -a stdout -a stdin bijoutrouvaille/fireward > generated.rules

To generate TypeScript rules

cat definitions.ward | docker run --rm -i -a stdout -a stdin bijoutrouvaille/fireward -c "--lang=typescript" > generated.ts


  -i FILE      --input=FILE                          Input fireward file instead of stdin
  -o FILE      --output=FILE                         Output file instead of stdout
  -s STRING    --string=STRING                       Input string
  -l language  --lang=language, --language=language  Output language. One of: rules, typescript.
  -V           --version                             Print version
  -h           --help                                Show help

--lang is rules by default, and is, therefore, optional. If -i is not provided, stdin is read. If -o is not provided, output goes to stdout.


Generate rules: fireward -i myrules.ward > firestore.rules

Generate TypeScript definitions: fireward -i myrules.ward --lang=typescript > MyTypings.ts

Rules Syntax

Fireward tries to keep things simple and easy to learn by mostly using the syntax that already exists in the two languages it generates: Firestore Rules and TypeScript. The basic steps in writing Fireward are: 1. Define a type with TypeScript-like syntax. 2. Assign it to routes written with Firestore Rules syntax. Therefore, the .ward file is essentially the Firestore rules augmented with TypeScript types.

Fireward will wrap the code with the boilerplate:

service cloud.firestore {  
  match /databases/{database}/documents {

Currently, it is an error to do so yourself.

Simple Example

type Name = { first: string, last?: string }
type User = { name: Name | string }

match /users/{id} is User {
  allow read: true;
  allow write: false;

Complete Example

rules_version = '2' // optional, see

type User = {
  name: { first: string, last: string }, // inline nested objects
  friends: string[], // a list of strings (string type not validated)
  tags: string[4], // a list of strings, max size 4 (string type IS validated)
  age?: int, // optional type
  verified: bool
  contact: Phone | Email // a union type
  uid: const string // const prevents editing this field later
  permissions: map // corresponds to `map` type in the rules and `Record<string, unknown>` in TS
type Phone = { number: int, country: int }
type Email = string

function isLoggedInUser(userId) { 
  // return keyword optional
  return request.auth!=null && request.auth.uid == userId; 

match /users/{userId} is User { 
  // read, write, create, update, list, get and delete conditions are allowed
  allow read, create, update: if isLoggedInUser(userId);
  allow delete: false;

Notes on Syntax


Firestore rules language' primitive types don't map exactly to JavaScript, so Fireward has to convert them when generating TypeScript definitions. In particular:

  • int and float map to TypeScript number
  • bool in rules maps to TS boolean
  • timestamp maps to {seconds: number, nanoseconds: number}|{isEqual: (other: any)=>boolean}. Snapshots will come as a timestamp ({seconds: number, nanoseconds: number}), but when writing to the database, you can assign, in addition to a timestamp, a server timestamp object (firebase.firestore.FieldValue.serverTimestamp()).


Union types are supported. Intersections are not. The usage is simple and demonstrated in the basic example above.


Firestore lists are supported and transpile to arrays or tuples in TS. The syntax is MyType[] or MyType[n]. The second variant will transpile to a MyType tuple up to n in size. For example, if n is 4 (MyType[4]), then the result will be a 0,1,2,3 or 4-tuple, basically, an array up to 4 in length. Check the top of the generated TS file for the exported types that represent it.

Important: the only way to ensure that the list of, say strings, contains strings is by using the tuple syntax above. Firestore does not have the capability to validate arbitrary size lists.

Optional Types and null

Unlike in Firebase Realitime Database, optional types differ from nulls. Optional types are indicated with a ? before the colon, e.g. {phone?: string}. Warning: if you are relying on TypeScript, this will allow you to define keys with value undefined, which Firestore may reject as an error. Firestore has no equivalent to the JavaScript undefined.

const Types

Fireward allows you to declare primitive types as const, as in the example above. A const field will permit being written to once, rejecting subsequent writes. By design, the update will also be permitted in situations where the previous value is null or optional and absent.

Warning: const current only works on primitive types. Marking a non-primitive as const will compile without error but do nothing.

Route Matching, Conditions and Functions

For the exception of assigning a type to a route, the syntax is identical to the Firestore rule language syntax.


Line comments are supported with //.

Splitting Across Files

planned but not yet supported


Contributions are welcome!

Please use, test, file issues, star and share Fireward with your Firebase friends.

Contributing Code

The project uses the stack tool and puts useful shortcuts, like make test, into the makefile.

The project was born from an exercise in monadic programming (based on Monads for Functional Programming by Wadler, and Thinking Functionally in Haskell, the chapter on Parsing), so the parser is written from scratch. It seems to be the same in concept as Parsec, but with less functionality.

Unit testing

Please unit test contributions and make sure all the tests are passing when submitting. The project makes that part easy and fun.


The project has been recently released, and some bugs are to be expected. The author will try to resolve them soon after they are reported.


[x] Add comments [x] Add error handling to the parser

  • Allow for importing files
  • Allow for read/write conditions within types
  • Add Windows and Linux release executables pipelines.
  • Namespace validation functions (e.g. isX for type X)



Project Statistics

Sourcerank 5
Repository Size 284 KB
Stars 50
Forks 4
Watchers 3
Open issues 1
Dependencies 7
Contributors 2
Tags 38
Last updated
Last pushed

Top Contributors See all

Bijou Trouvaille Kamil Biela

Packages Referencing this Repo

A simple and readable language for Firestore security rules, similar to Firebase Bolt.
Latest release 1.2.2 - Updated - 50 stars

Recent Tags See all

1.2.2 December 07, 2019
1.2.1 December 06, 2019
1.1.4 November 29, 2019
1.1.3 November 20, 2019
1.1.2 November 20, 2019
1.1.1 November 12, 2019
1.1.0 October 30, 2019
1.0.0 October 20, 2019
0.0.28 October 20, 2019
0.0.27 September 15, 2019
0.0.27 September 15, 2019
0.0.25 September 07, 2019
0.0.24 September 04, 2019
0.0.23 September 04, 2019
0.0.21 September 04, 2019

Something wrong with this page? Make a suggestion

Last synced: 2019-09-07 01:43:19 UTC

Login to resync this repository