# How to Use the Zstandard Simple Compression API in C

> Learn to use the Zstandard simple compression API in C with ZSTD_compress and ZSTD_decompress. This guide simplifies one-shot compression and decompression for your projects.

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

---

**The Zstandard simple compression API enables one-shot compression and decompression through `ZSTD_compress()` and `ZSTD_decompress()`, which automatically manage internal contexts and require only source data, destination buffers, and a compression level.**

The facebook/zstd library provides a straightforward interface for memory-to-memory compression tasks where data fits comfortably in RAM. These functions, declared in [`lib/zstd.h`](https://github.com/facebook/zstd/blob/main/lib/zstd.h) as part of the public `ZSTDLIB_API`, handle context creation and cleanup automatically, making them ideal for quick integration without explicit state management.

## Core Functions of the Simple API

The simple compression API centers on two primary functions:

- `ZSTD_compress()` – Compresses a complete source buffer into a destination buffer in a single call.
- `ZSTD_decompress()` – Restores a compressed buffer back to its original uncompressed form.

Both functions return the number of bytes written (as `size_t`) on success. On failure, they return an error code that you must check using `ZSTD_isError()` and describe with `ZSTD_getErrorName()`. According to the source code in [`lib/zstd.c`](https://github.com/facebook/zstd/blob/main/lib/zstd.c), these functions wrap the lower-level streaming engine by creating internal contexts, executing the operation, and freeing resources before returning.

## Buffer Sizing and Error Handling

Before compression, you must allocate a destination buffer large enough to hold the worst-case compressed output. The helper `ZSTD_compressBound(srcSize)` calculates this maximum size based on the input length. Always use this value to prevent buffer overflows during `ZSTD_compress()` operations.

For decompression, you typically need to know the original data size. The function `ZSTD_getFrameContentSize()` inspects the compressed frame header and returns the uncompressed size without performing full decompression. If the original size is stored in the frame header, you can allocate an exact-sized buffer; otherwise, you must provide a buffer large enough for your use case.

## Compressing Data with ZSTD_compress

The following example demonstrates basic compression using the simple API. It allocates a buffer using `ZSTD_compressBound()`, calls `ZSTD_compress()` with compression level `3`, and validates the result.

```c
/* compress_example.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "zstd.h"

int main(void) {
    const char *input = "Hello Zstandard! This text will be compressed.";
    size_t srcSize = strlen(input);
    int level = 3;                           // standard compression level

    /* Allocate a destination buffer large enough for worst-case size */
    size_t maxCompressedSize = ZSTD_compressBound(srcSize);
    void *compressed = malloc(maxCompressedSize);
    if (!compressed) { fprintf(stderr, "malloc failed\n"); return 1; }

    size_t cSize = ZSTD_compress(compressed, maxCompressedSize,
                                 input, srcSize, level);
    if (ZSTD_isError(cSize)) {
        fprintf(stderr, "compression error: %s\n",
                ZSTD_getErrorName(cSize));
        free(compressed);
        return 1;
    }

    printf("Compressed %zu bytes into %zu bytes (level %d)\n",
           srcSize, cSize, level);
    free(compressed);
    return 0;
}

```

Compile the example by linking against the zstd library:

```bash
gcc compress_example.c -lzstd -o compress_example

```

## Decompressing Data with ZSTD_decompress

For decompression, first query the frame content size to allocate the correct buffer, then call `ZSTD_decompress()`. The following example assumes `compressed` and `cSize` variables exist from a previous compression operation.

```c
/* decompress_example.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "zstd.h"

int main(void) {
    /* Assume `compressed` and `cSize` were produced by the previous example */
    extern void *compressed;   /* replace with actual pointer */
    extern size_t cSize;       /* replace with actual size   */

    /* First, retrieve the original size (optional but useful) */
    unsigned long long origSize = ZSTD_getFrameContentSize(compressed, cSize);
    if (origSize == ZSTD_CONTENTSIZE_UNKNOWN) {
        fprintf(stderr, "Original size unknown – use a large buffer\n");
        origSize = 1024;  /* fallback */
    }

    void *decompressed = malloc((size_t)origSize);
    if (!decompressed) { fprintf(stderr, "malloc failed\n"); return 1; }

    size_t dSize = ZSTD_decompress(decompressed, (size_t)origSize,
                                   compressed, cSize);
    if (ZSTD_isError(dSize)) {
        fprintf(stderr, "decompression error: %s\n",
                ZSTD_getErrorName(dSize));
        free(decompressed);
        return 1;
    }

    printf("Decompressed %zu bytes: \"%.*s\"\n", dSize,
           (int)dSize, (char *)decompressed);
    free(decompressed);
    return 0;
}

```

## Configuring Compression Levels

The simple API accepts an integer compression level ranging from `-ZSTD_minCLevel()` up to `ZSTD_maxCLevel()`. The default level is `3`, which balances speed and compression ratio effectively. Negative levels prioritize compression speed over ratio, suitable for real-time applications, while higher values increase compression density at the cost of CPU time and latency.

## Implementation Details and Thread Safety

The implementation in [`lib/zstd.c`](https://github.com/facebook/zstd/blob/main/lib/zstd.c) creates a compression or decompression context internally, executes the operation using the streaming engine, and destroys the context before returning. This self-contained design eliminates the need for explicit `ZSTD_CCtx` or `ZSTD_DCtx` management in client code.

The simple API functions are thread-safe as implemented in the source code. You may call `ZSTD_compress()` or `ZSTD_decompress()` concurrently from multiple threads, provided each invocation uses distinct source and destination buffers. No locks are required because the functions do not share mutable state between calls.

## Summary

- **Single-call compression**: Use `ZSTD_compress()` with a destination buffer sized via `ZSTD_compressBound()`.
- **Single-call decompression**: Use `ZSTD_decompress()` after optionally querying the original size with `ZSTD_getFrameContentSize()`.
- **Error checking**: Always validate return values using `ZSTD_isError()` and describe failures with `ZSTD_getErrorName()`.
- **No context required**: The simple API manages internal contexts automatically as implemented in [`lib/zstd.c`](https://github.com/facebook/zstd/blob/main/lib/zstd.c).
- **Thread-safe**: Concurrent calls are safe when using separate input and output buffers per thread.

## Frequently Asked Questions

### What is the difference between the simple API and the streaming API in zstd?

The simple API performs one-shot compression and decompression using `ZSTD_compress()` and `ZSTD_decompress()`, automatically managing internal contexts declared in [`lib/zstd.h`](https://github.com/facebook/zstd/blob/main/lib/zstd.h). The streaming API requires explicit context objects (`ZSTD_CCtx` or `ZSTD_DCtx`) and processes data in chunks through `ZSTD_compressStream()` or `ZSTD_decompressStream()`, making it suitable for large files or network streams where memory is constrained.

### How do I determine the correct size for the decompression buffer?

Call `ZSTD_getFrameContentSize()` on the compressed frame to extract the original uncompressed size from the header. If this returns `ZSTD_CONTENTSIZE_UNKNOWN`, you must either allocate a buffer large enough for your application's maximum expected size or switch to the streaming API to process data incrementally without requiring the full size upfront.

### What compression level should I use for general-purpose data?

Use level `3`, which is the default and provides an optimal balance between compression speed and ratio according to the [`lib/zstd.h`](https://github.com/facebook/zstd/blob/main/lib/zstd.h) definitions. Use negative levels (down to `-ZSTD_minCLevel()`) for speed-critical applications like real-time logging, or levels above `3` (up to `ZSTD_maxCLevel()`) for archival storage where compression density matters more than throughput.

### Are the simple compression functions thread-safe?

Yes. The functions are thread-safe as long as each thread operates on distinct source and destination buffers. The implementation in [`lib/zstd.c`](https://github.com/facebook/zstd/blob/main/lib/zstd.c) creates and destroys internal contexts per call, so no shared mutable state exists between invocations, allowing safe concurrent usage without synchronization primitives.