---
title: "Save PDF annotations to external storage in JavaScript | Nutrient"
canonical_url: "https://www.nutrient.io/guides/web/annotations/save/to-external-storage/"
md_url: "https://www.nutrient.io/guides/web/annotations/save/to-external-storage.md"
last_updated: "2026-06-09T10:35:39.058Z"
description: "Save PDF annotations to external storage using JavaScript with Nutrient Web SDK. Use Instant JSON for efficient change tracking or export the full PDF with annotations."
---

# Save annotations to external storage

You have two options to save annotation changes to external storage: saving the changes only, or saving the whole PDF.

## Saving the changes only

Our recommendation for storing changes to annotations is through [Instant JSON](https://www.nutrient.io/guides/web/importing-exporting/instant-json.md). Importing and exporting a JSON file with the changes made to a document instead of doing this with the full PDF each time significantly reduces the bandwidth used.

If you just want to save the annotation changes made by the user on the original PDF, use [`Instance#exportInstantJSON`](https://www.nutrient.io/api/web/NutrientViewer.Instance.html#exportInstantJSON) to export a JSON containing all the changes. Store this separately and apply it when you load the original PDF next time using [`Configuration#instantJSON`](https://www.nutrient.io/api/web/NutrientViewer.Configuration.html#instantJSON) (only without Document Engine). With this approach, you won’t have to repeatedly save the PDF file, and you can use the original PDF every time.

See the [importing and exporting](https://www.nutrient.io/guides/web/importing-exporting/instant-json.md) section of our Instant JSON reference guide for examples of how to use Instant JSON.

When using Nutrient Web SDK with Document Engine, you can still use `Instance#exportInstantJSON()` to export annotation changes to external storage. Follow the [guides](https://www.nutrient.io/guides/document-engine/annotations/import-and-export/instant-json.md) for an in-depth example of how to use Instant JSON.

## Saving the whole PDF

Export the modified PDF as an array buffer by using [`Instance#exportPDF`](https://www.nutrient.io/api/web/NutrientViewer.Instance.html#exportPDF) and triggering a download, as explained in the [save a document to local storage](https://www.nutrient.io/guides/web/save-a-document/to-local-storage.md) guide.

## Ensuring annotations have been persisted

If you want to ensure that an annotation has been persisted by the backend, use the [`Instance.ensureChangesSaved`](https://www.nutrient.io/api/web/NutrientViewer.Instance.html#ensureChangesSaved) endpoint. This endpoint takes an array of changes and returns a promise that resolves to the array of changes in their persisted state as soon as they’re saved by the server. This means if you update the annotation before it has been saved by the server, [`Instance.ensureChangesSaved`](https://www.nutrient.io/api/web/NutrientViewer.Instance.html#ensureChangesSaved) will return the updated annotation, even though [`Instance.ensureChangesSaved`](https://www.nutrient.io/api/web/NutrientViewer.Instance.html#ensureChangesSaved) might have been called before the annotation was updated. Since this method takes exactly the same argument that’s returned by the
[`Instance#create`](https://www.nutrient.io/api/web/NutrientViewer.Instance.html#create) method, you can easily chain the calls. The ID can be used with the [backend API](https://www.nutrient.io/api/reference/document-engine/upstream/) and is unique inside a document:

```js

NutrientViewer.load(configuration).then(async (instance) => {
  const createdAnnotations = await instance.create(newAnnotation);
  const [savedAnnotation] = await instance.ensureChangesSaved(
    createdAnnotations
  );
  console.log(savedAnnotation.id); // => '01BS964AM5Z01J9MKBK64F22BQ'
});

```

```js

NutrientViewer.load({...configuration,
  autoSaveMode: NutrientViewer.AutoSaveMode.DISABLED
}).then(async (instance) => {
  const newAnnotation = new NutrientViewer.Annotations.TextAnnotation({
    pageIndex: 0,
    boundingBox: new NutrientViewer.Geometry.Rect({
      left: 100,
      top: 200,
      width: 150,
      height: 75
    }),
    text: {
      format: "plain",
      value: "foo"
    }
  });
  console.log(newAnnotation.text); // => 'foo'
  const createdAnnotations = await instance.create(newAnnotation);
  const savedAnnotationPromise = instance.ensureChangesSaved(
    createdAnnotations
  );
  const updatedAnnotations = await instance.update(
    createdAnnotations[0].set("text", "bar")
  );
  instance.save();
  const [savedAnnotation] = await savedAnnotationPromise;
  console.log(savedAnnotation.text); // => 'bar'
});

```
---

## Related pages

- [Auto saving annotations](/guides/web/annotations/annotation-saving-mechanism.md)
- [Embedding annotations in a PDF](/guides/web/annotations/save/embed-into-pdf.md)
- [Saving PDF annotations](/guides/web/annotations/save/overview.md)

