Guides: Add RavenDB to an Existing Azure Functions Project (Node.js)


Before We Get Started

You will need the following before continuing:

Starting from scratch?

For a brand new Azure Functions app, we recommend using the RavenDB Azure Functions Node.js template which is set up with PEM certificate support.
You can also reference the template to see how the integration is set up.

Installing the RavenDB Client SDK

Get started by installing the ravendb npm package in your project which provides the Node.js client SDK.

Using npm:

npm install ravendb

Initializing the Document Store

Import the DocumentStore from ravendb package to create a new instance with the required configuration and initialize your connection to RavenDB by calling the initialize method.
You can then export a function to initialize a document session to use in your Azure functions.

Example db.js Node module:

import { DocumentStore } from "ravendb";

const documentStore = new DocumentStore(
  ["https://a.free.mycompany.ravendb.cloud"],
  "demo",
  // authOptions
};

var initialized = false;

function initialize() {
    if (initialized) return;
    documentStore.initialize();
    initialized = true;
}

export function openAsyncSession() {
    if (!initialized) {
        initialize();
    }

    return documentStore.openAsyncSession();
}

For more on what options are available, see Creating a Document Store.

Warm vs. Cold Starts

In Azure Functions, the instance will be shared across function invocations if the Function is warmed up, otherwise it will be constructed each time the function warms up. For more, see Deployment Considerations.

You can set options manually but it's more likely you'll want to configure support for app settings.

Adding Support for App Settings

You will need a way to pass options to the DocumentStore on your local machine and when deployed to Azure.

Node.js Azure Functions support a local.settings.json file which you can use to add additional settings locally. For example:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "DB_URLS": "https://a.free.company.ravendb.cloud",
    "DB_NAME": "demo",
    "DB_CERT_PATH": "../certs/company.client.certificate.pfx"
  }
}

You can then load environment variables through process.env:

import { readFileSync } from "fs";
import { DocumentStore } from "ravendb";

var documentStore;
var initialized = false;

function initialize() {
    if (initialized) return;

    const authOptions = {
      type: "pfx",
      // Read .pfx file using fs.readFileSync
      certificate: readFileSync(process.env.DB_CERT_PATH)
    };

    documentStore = new DocumentStore(
      process.env.DB_URLS.split(","), // Split by "," separator
      process.env.DB_NAME,
      authOptions
    };
    documentStore.initialize();

    initialized = true;
}

export function openAsyncSession() {
    if (!initialized) {
        initialize();
    }

    return documentStore.openAsyncSession();
}

Configuring Support for Certificates

RavenDB uses client certificate authentication (mutual TLS) to secure your database connection.
The Node.js client SDK supports .pfx files or .pem files which is passed to the authOptions.certificate option.
There are multiple ways to load a certificate:

  • Load from .pfx files
  • Load from PEM-encoded certificate
  • Load from Azure Key Vault

Load from .pfx Files

You can load PFX files with or without a password by providing the certificate buffer using authOptions.certificate:

const authOptions = {
    type: "pfx",
    // Read .pfx file using fs.readFileSync
    certificate: readFileSync("../cert/company.client.certificate.pfx"),
    // Optionally provide the password
    password: "<CERT_PASSWORD>"
};

documentStore = new DocumentStore(
    ["https://a.free.company.ravendb.cloud"],
    "demo",
    authOptions
};
documentStore.initialize();

If the .pfx file requires a password, provide it using password option.
However, keep in mind that using an absolute physical file path or a password requires manual steps for every developer working on a project to configure.

Avoid uploading or deploying .pfx files

PFX files can be compromised, especially if they are not password-protected.
Using a physical file also makes it hard to manage and rotate when they expire.
They are only recommended for ease-of-use on your local machine.
For production, it is better to use the Certificate Store method or Azure Key Vault.

Load from PEM-encoded certificate

For Node.js-based Azure Functions, it's recommended to use a PEM-encoded certificate that can be provided through Azure app settings without deploying any files.

Unlike a .pfx file, a PEM-encoded certificate is plain-text encoded:

-----BEGIN CERTIFICATE-----
MIIFCzCCAvO...
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAK...
-----END RSA PRIVATE KEY-----

To pass a PEM-encoded certificate, you can read an environment variable like DB_CERT_PEM and set authOptions using the pem certificate type:

const authOptions = {
    type: "pem",
    certificate: process.env.DB_CERT_PEM
};

documentStore = new DocumentStore(
    ["https://a.free.company.ravendb.cloud"],
    "demo",
    authOptions
};
documentStore.initialize();

Normalizing PEM certificates

Be aware that the Azure portal removes line endings and you will need to manually normalize the value for PEM parsing to succeed. If you are setting the value in the local.settings.json file, you will need to format the value for JSON using a stringify tool.

Here is how the starter template adds support for loading certificates using a DB_CERT_PEM environment variable:

import { EOL } from "os";
import { readFile } from "fs/promises";
import { DocumentStore } from "ravendb";

let store;
let initialized = false;

export async function initializeDb({
  urls,
  databaseName,
  dbCertPassword,
  dbCertPath,
  dbCertPem,
  customize,
}) {
  if (initialized) return;

  let authOptions = undefined;

  if (dbCertPath) {
    authOptions = await getAuthOptionsFromCertificatePath(
      dbCertPath,
      dbCertPassword
    );
  } else if (dbCertPem) {
    authOptions = getAuthOptionsFromCertPem(dbCertPem);
  }

  store = new DocumentStore(urls, databaseName, authOptions);

  if (customize) {
    customize(store.conventions);
  }

  store.initialize();

  initialized = true;

  return store;
}

async function getAuthOptionsFromCertificatePath(
  dbCertPath,
  dbCertPassword
) {
  return {
    certificate: await readFile(dbCertPath),
    password: dbCertPassword,
    type: "pfx",
  };
}

function getAuthOptionsFromCertPem(dbCertPem) {
  let certificate = dbCertPem;
  const isMissingLineEndings = !dbCertPem.includes(EOL);

  if (isMissingLineEndings) {
    // Typically when pasting values into Azure env vars
    certificate = normalizePEM(certificate);
  }

  return {
    certificate,
    type: "pem",
  };
}

function normalizePEM(pem: string): string {
  return pem.replace(PEM_REGEX, (match, certSection, certSectionBody) => {
    const normalizedCertSectionBody = certSectionBody.replace(/\s/g, EOL);
    return `-----BEGIN ${certSection}-----${EOL}${normalizedCertSectionBody.trim()}${EOL}-----END ${certSection}-----${EOL}`;
  });
}

const PEM_REGEX =
  /-----BEGIN ([A-Z\s]+)-----(\s?[A-Za-z0-9+\/=\s]+?\s?)-----END \1-----/gm;

export function openDbSession(opts) {
  if (!initialized)
    throw new Error(
      "DocumentStore is not initialized yet. Must `initializeDb()` before calling `openDbSession()`."
    );
  return store.openSession(opts);
}

This supports using .pfx files or a PEM-encoded certificate, if provided.
It normalizes the PEM value if it does not contain line endings.

Load from Azure Key Vault

Azure Key Vault is a paid service that allows you to store, retrieve, and rotate encrypted secrets including X.509 Certificates. This is recommended for more robust certificate handling.

Using the SecretsClient, you can load secrets from Key Vault.
However, you will need to use the CertificateClient to retrieve a certificate from the vault.

For more, see the sample code for using CertificateClient.

Configuring Azure

You will need to configure certificate authentication in Azure. Depending on the method you choose above, the steps vary.

Specifying Path to Certificate

If you are deploying a physical .pfx file, you can specify the DB_CERT_PATH and DB_PASSWORD app settings.

Specifying PEM Certificate

If you are loading a PEM-encoded certificate, follow the steps below to make your .pem certificate available to your Azure Functions:

.NET update Azure app settings

.NET update Azure app settings

  1. Find the .pem certificate provided by RavenDB client certificate package
  2. Copy its full contents
  3. Go to your Azure Functions dashboard in the Portal
  4. Click the Application Settings menu
  5. Modify or add the app setting for DB_CERT_PEM and paste the contents of your .pem file

These values will override local.settings.json once deployed on Azure.

Next Steps