Azure Functions: Cosmos DB Output Bindings

Learn how to use output bindings to write data to Azure Cosmos DB from your Azure Functions.

Overview

Azure Functions provides output bindings for Azure Cosmos DB, simplifying the process of writing data to your Cosmos DB collections. Instead of manually managing SDKs and connection strings within your function code, you can declare an output binding in your function's configuration, and the Functions runtime will handle the persistence of data to Cosmos DB.

This binding allows you to:

How it Works

When you configure an output binding for Cosmos DB, you specify the target database, collection (or container), and optionally a partition key. Your function then needs to return or pass a value to this output binding, and the Functions runtime takes care of writing that value as a document to your Cosmos DB instance.

The most common way to use an output binding is by returning a value from your function. For more complex scenarios or when writing multiple items, you can use the out parameter.

Configuration

You define Cosmos DB output bindings in your function's function.json file (for JavaScript, Python, and PowerShell) or via attributes (for C#).

function.json Example (JavaScript, Python, PowerShell)

`function.json`

{
  "scriptFile": "../run.py",
  "bindings": [
    {
      "name": "req",
      "type": "httpTrigger",
      "direction": "in",
      "methods": [ "get", "post" ],
      "authLevel": "function"
    },
    {
      "name": "doc",
      "type": "cosmosDB",
      "direction": "out",
      "databaseName": "TasksDB",
      "collectionName": "Tasks",
      "createIfNotExists": false,
      "connectionStringSetting": "CosmosDBConnection"
    },
    {
      "name": "$return",
      "type": "http",
      "direction": "out"
    }
  ]
}

Key properties in the configuration:

C# Attribute Example

C# Function Signature

using Microsoft.Azure.WebJobs;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

public static class CreateItem
{
    [FunctionName("CreateItem")]
    public static IActionResult Run(
        [HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequest req,
        [CosmosDB(
            databaseName: "TasksDB",
            collectionName: "Tasks",
            ConnectionStringSetting = "CosmosDBConnection",
            CreateIfNotExists = false
        )] out dynamic document)
    {
        // Function logic here...
        var newItem = new { /* item properties */ };
        document = newItem; // Assign to output binding

        return new OkResult();
    }
}

Explanation

In C#, the [CosmosDB] attribute is used to declare the output binding. The out dynamic document parameter represents the output binding. You assign the data you want to save to Cosmos DB to this parameter.

Writing Data

Using the Return Value (JavaScript/TypeScript)

If your function has a single output binding and it's the default $return binding, you can simply return the object.

module.exports = async function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');

    const newItem = {
        id: context.invocationId,
        taskName: req.body.taskName,
        isComplete: false
    };

    context.log('Sending item to Cosmos DB output binding:', newItem);
    context.done(null, newItem); // Return the item to the $return output binding
};

Using an `out` Parameter (JavaScript)

For more explicit control or when you have multiple outputs, use an out parameter.

module.exports = async function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');

    const newItem = {
        id: context.invocationId,
        taskName: req.body.taskName,
        isComplete: false
    };

    context.log('Writing item to Cosmos DB output binding:', newItem);
    context.bindings.doc = newItem; // Assign to the 'doc' output binding

    context.res = {
        status: 201,
        body: "Item created successfully."
    };
    context.done();
};

Using an `out` Parameter (Python)

import logging
import azure.functions as func

def main(req: func.HttpRequest, doc: func.Out[func.Document]) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    task_name = req.get_json().get('taskName')
    if not task_name:
        return func.HttpResponse("Please provide a taskName in the request body", status_code=400)

    new_item = {
        "id": str(uuid.uuid4()), # Using uuid for unique IDs
        "taskName": task_name,
        "isComplete": False
    }

    logging.info(f"Writing item to Cosmos DB output binding: {new_item}")
    doc.set(func.Document.from_dict(new_item))

    return func.HttpResponse("Item created successfully.", status_code=201)

Partition Keys

For partitioned collections, you must specify a partition key. The Functions runtime uses this value to route the document to the correct partition.

Specifying Partition Key in function.json

`function.json` (with partition key)

{
  "scriptFile": "../run.py",
  "bindings": [
    {
      "name": "req",
      "type": "httpTrigger",
      "direction": "in",
      "methods": [ "post" ],
      "authLevel": "function"
    },
    {
      "name": "doc",
      "type": "cosmosDB",
      "direction": "out",
      "databaseName": "TasksDB",
      "collectionName": "Tasks",
      "connectionStringSetting": "CosmosDBConnection",
      "partitionKey": "/userId"
    },
    {
      "name": "$return",
      "type": "http",
      "direction": "out"
    }
  ]
}

You can set the partition key value dynamically in your code.

Setting Partition Key Dynamically (JavaScript)

module.exports = async function (context, req) {
    const userId = req.body.userId;
    const taskName = req.body.taskName;

    if (!userId || !taskName) {
        context.res = { status: 400, body: "Please provide userId and taskName." };
        return;
    }

    const newItem = {
        id: context.invocationId,
        userId: userId,
        taskName: taskName,
        isComplete: false
    };

    // The partitionKey configuration in function.json uses a placeholder.
    // The runtime will use the value from the document's 'userId' property.
    // Alternatively, you can set the partition key explicitly on the output object if needed,
    // but usually the runtime infers it from the document structure based on the binding config.
    context.bindings.doc = newItem;

    context.res = {
        status: 201,
        body: "Item created successfully."
    };
};

Best Practices and Considerations

Troubleshooting

If you encounter issues: