# How to Use the Basic Zstd Decompression API: A Complete Guide

> Master the basic Zstd decompression API with this guide. Learn to use ZSTD_decompress, allocate buffers, and check for errors for efficient data handling.

- Repository: [Meta/zstd](https://github.com/facebook/zstd)
- Tags: how-to-guide
- Published: 2026-09-09

---

**The basic zstd decompression API provides a one-shot memory-to-memory interface centered on `ZSTD_decompress()`, requiring callers to pre-allocate destination buffers and verify results using `ZSTD_isError()` and `ZSTD_getErrorName()`.**

The facebook/zstd library offers a minimal, high-performance one-shot decompression interface for applications that process complete frames in memory. This basic zstd decompression API gives you full control over memory allocation while eliminating the overhead of persistent decompression contexts. Understanding the proper sequence of calls—from querying frame metadata to handling error codes—ensures robust integration into performance-critical C and C++ applications.

## Core API Functions in lib/zstd.h

The public API surface for basic decompression resides in [`lib/zstd.h`](https://github.com/facebook/zstd/blob/main/lib/zstd.h). Three functions form the complete workflow for decompressing a frame with known or unknown size.

### Querying Frame Size with ZSTD_getFrameContentSize

Before allocating memory, determine the decompressed size by reading the frame header. The function declared at lines 779-796 in [`lib/zstd.h`](https://github.com/facebook/zstd/blob/main/lib/zstd.h) extracts the original content size:

```c
unsigned long long ZSTD_getFrameContentSize(const void* src, size_t srcSize);

```

This returns:

- The exact decompressed size (if stored in the frame)
- `ZSTD_CONTENTSIZE_UNKNOWN` when the size was not stored (e.g., streaming compression without pledged size)
- `ZSTD_CONTENTSIZE_ERROR` if the frame header is corrupted

### Decompressing with ZSTD_decompress

The one-shot function declared at lines 164-174 performs the actual decompression:

```c
size_t ZSTD_decompress(void* dst, size_t dstCapacity,
                       const void* src, size_t compressedSize);

```

This function creates a temporary decompression context internally, parses the frame header, and expands the compressed payload into `dst`. The `dstCapacity` must be greater than or equal to the original size; otherwise, it returns `ZSTD_errorDstSizeTooSmall`.

### Error Detection with ZSTD_isError

All Zstandard functions return `size_t` values that may represent errors. Lines 59-62 in [`lib/zstd.h`](https://github.com/facebook/zstd/blob/main/lib/zstd.h) provide the error checking interface:

```c
static unsigned int ZSTD_isError(size_t code);
const char* ZSTD_getErrorName(size_t code);

```

Use `ZSTD_isError()` to test return values and `ZSTD_getErrorName()` to obtain human-readable error strings.

## Step-by-Step Implementation

Follow this deterministic workflow to decompress frames safely.

1. Call `ZSTD_getFrameContentSize()` to read the frame header and determine the required buffer size.
2. Allocate a destination buffer of at least the returned size (or use a safe upper bound if the size is unknown).
3. Invoke `ZSTD_decompress()` with the source buffer, destination buffer, and capacity.
4. Verify the return value with `ZSTD_isError()`; on success, the value equals the number of bytes written.

This design intentionally places memory management responsibility on the caller, enabling deterministic behavior on constrained systems and avoiding hidden allocations.

## Practical Code Examples

### Decompressing When Size Is Known

When the frame contains the original size metadata (the common case for one-shot compression):

```c
#include <stdio.h>
#include <stdlib.h>
#include "zstd.h"

int main(void) {
    /* src points to a ZSTD-compressed frame and srcSize is its exact length */
    const void *src = /* … */;
    size_t srcSize = /* … */;

    /* 1. Query the original size stored in the frame header */
    unsigned long long originalSize = ZSTD_getFrameContentSize(src, srcSize);
    if (originalSize == ZSTD_CONTENTSIZE_ERROR) {
        fprintf(stderr, "Invalid ZSTD frame header\n");
        return 1;
    }
    if (originalSize == ZSTD_CONTENTSIZE_UNKNOWN) {
        fprintf(stderr, "Original size not stored – need streaming API\n");
        return 1;
    }

    /* 2. Allocate destination buffer */
    void *dst = malloc((size_t)originalSize);
    if (!dst) { perror("malloc"); return 1; }

    /* 3. Decompress */
    size_t ret = ZSTD_decompress(dst, (size_t)originalSize, src, srcSize);
    if (ZSTD_isError(ret)) {
        fprintf(stderr, "Decompression error: %s\n", ZSTD_getErrorName(ret));
        free(dst);
        return 1;
    }

    /* ret equals originalSize on success */
    printf("Decompressed %zu bytes\n", ret);

    free(dst);
    return 0;
}

```

### Handling Unknown Frame Sizes

When `ZSTD_getFrameContentSize()` returns `ZSTD_CONTENTSIZE_UNKNOWN`, allocate a safe upper bound or switch to streaming:

```c
#define MAX_OUT_SIZE (16 * 1024 * 1024)

void *dst = malloc(MAX_OUT_SIZE);
size_t ret = ZSTD_decompress(dst, MAX_OUT_SIZE, src, srcSize);
if (ZSTD_isError(ret)) {
    /* Checks for ZSTD_errorDstSizeTooSmall or ZSTD_errorCorruptFrame */
    fprintf(stderr, "Error: %s\n", ZSTD_getErrorName(ret));
} else {
    printf("Successfully decompressed %zu bytes\n", ret);
}

```

This pattern prevents buffer overruns at the cost of potentially over-allocating memory.

### Minimal Error Handling Wrapper

For applications requiring strict failure handling, wrap the decompression call:

```c
size_t zstd_decompress_or_die(void *dst, size_t dstCap,
                               const void *src, size_t srcSize) {
    size_t r = ZSTD_decompress(dst, dstCap, src, srcSize);
    if (ZSTD_isError(r)) {
        fprintf(stderr, "ZSTD_decompress failed: %s\n",
                ZSTD_getErrorName(r));
        abort();
    }
    return r;
}

```

## Key Source Files

Understanding the implementation locations helps with debugging and advanced customization:

- **[`lib/zstd.h`](https://github.com/facebook/zstd/blob/main/lib/zstd.h)**: Public API header exposing `ZSTD_decompress` (lines 164-174), `ZSTD_getFrameContentSize` (lines 779-796), and error helpers (lines 59-62).
- **[`lib/zstd_errors.h`](https://github.com/facebook/zstd/blob/main/lib/zstd_errors.h)**: Defines error codes (e.g., `ZSTD_errorDstSizeTooSmall`) and `ZSTD_getErrorName`.
- **[`lib/decompress/zstd_decompress_internal.h`](https://github.com/facebook/zstd/blob/main/lib/decompress/zstd_decompress_internal.h)**: Internal implementation details of the one-shot decompression routine.
- **[`doc/educational_decoder/zstd_decompress.h`](https://github.com/facebook/zstd/blob/main/doc/educational_decoder/zstd_decompress.h)**: Educational documentation and simplified usage patterns.

## Summary

- The basic zstd decompression API centers on `ZSTD_decompress()` in [`lib/zstd.h`](https://github.com/facebook/zstd/blob/main/lib/zstd.h), providing stateless, one-shot decompression without persistent context allocation.
- Always query the frame size first using `ZSTD_getFrameContentSize()` to allocate appropriately sized buffers; handle `ZSTD_CONTENTSIZE_UNKNOWN` by allocating a safe upper bound or switching to the streaming API.
- Verify all return values using `ZSTD_isError()` and obtain diagnostic messages via `ZSTD_getErrorName()`.
- The API explicitly does not allocate memory, giving you full control over buffer management and enabling deterministic performance characteristics.

## Frequently Asked Questions

### What is the difference between ZSTD_decompress and the streaming API?

`ZSTD_decompress()` is a one-shot function that decompresses entire frames in a single call, internally creating a temporary decompression context and then discarding it. The streaming API uses a persistent `ZSTD_DCtx` object to process data incrementally, which is necessary for frames larger than available memory or for continuous data streams. Use the basic API for discrete, memory-resident frames; use streaming for large or unbounded data.

### How do I handle frames where the original size is unknown?

When `ZSTD_getFrameContentSize()` returns `ZSTD_CONTENTSIZE_UNKNOWN`, the compressor did not store the decompressed size in the frame header. You must either allocate a buffer using a known safe upper bound (accepting that `ZSTD_decompress()` may return `ZSTD_errorDstSizeTooSmall` if insufficient) or switch to the streaming decompression API. This commonly occurs when compressing with the streaming API without providing a pledged output size.

### What error codes can ZSTD_decompress return?

According to [`lib/zstd_errors.h`](https://github.com/facebook/zstd/blob/main/lib/zstd_errors.h), common errors include `ZSTD_errorDstSizeTooSmall` (destination buffer smaller than original size), `ZSTD_errorCorruptFrame` (invalid input data), and memory allocation failures. All errors are detectable via `ZSTD_isError()` and convertible to descriptive strings via `ZSTD_getErrorName()`. On success, the function returns the number of bytes written, which always equals the original decompressed size.

### Is the basic zstd decompression API thread-safe?

Yes, `ZSTD_decompress()` is thread-safe because it creates a temporary internal context for each call and does not modify global state. However, you must ensure that the source and destination buffers are not accessed by other threads during the operation. For scenarios requiring persistent dictionaries or custom memory allocators, use the explicit context API with `ZSTD_DCtx` objects instead of the basic one-shot interface.