---
title: "Pine Script: Libraries"
slug: "pine-script-libraries"
category: "coding"
tags: ["coding", "pine-script", "tradingview", "libraries", "reusability"]
status: "stable"
last_updated: 2026-08-14
summary: "Declare Pine v6 libraries with library(), export typed functions, version them, and import them in indicators and strategies."
related: ["[[coding/pine-script]]", "[[coding/pine-script-indicators]]", "[[coding/pine-script-strategies]]", "[[coding/pine-script-security]]", "[[coding/general-principles]]"]
---

## Overview

A Pine Script library packages reusable functions that can be imported by indicators and strategies. Use libraries to avoid copy-pasting the same math into every script. Shared logic in a library means a bug fix applies to every consumer with one version bump, rather than requiring a manual edit in every script that copied the code. This mirrors the DRY principle in [[coding/general-principles]]. Libraries cannot contain `plot()`, `strategy.*`, or `input.*` calls; they export pure functions only.

## Declare with `library()` and set exportable functions

The `library()` call at the top declares the script as a library. Every exported function must have a `// @function` annotation so TradingView can generate hover documentation.

```pine
//@version=6
// @description Volatility and position-sizing utilities
library("VolUtils", overlay=false)

// @function Computes ATR-based stop distance
// @param src        Series to compute ATR from
// @param atrLen     ATR period
// @param multiplier ATR multiplier for stop distance
// @returns Stop distance in price units
export atrStop(series float src, simple int atrLen, simple float multiplier) =>
    ta.atr(atrLen) * multiplier
```

The `export` keyword makes the function visible to importers. Functions without `export` are private to the library. Use private functions for shared intermediate calculations that callers do not need directly.

## Type function parameters explicitly

Type annotations are required for exported functions. They prevent silent type coercion that can cause incorrect values at runtime.

Pine types for parameters:
- `series float` / `series int` / `series bool`: bar-by-bar series (most common)
- `simple float` / `simple int` / `simple bool`: single value, evaluated once per script execution, not per bar
- `input float` / `input int` / `input bool`: value comes from an `input.*` call in the caller
- `const float` / `const int` / `const bool`: compile-time constant

Use `simple int` for length parameters like ATR period. Using `series int` on a length argument that changes bar-by-bar causes a runtime error in built-in functions like `ta.atr`.

## Return typed tuples for multi-value functions

Functions can return multiple values as a tuple. Annotate the return type for clarity:

```pine
// @function Returns upper and lower Keltner Channel bands
// @param src    Price source series
// @param emalen EMA period
// @param atrlen ATR period
// @param mult   ATR multiplier
// @returns [upper, mid, lower]
export keltner(series float src, simple int emalen, simple int atrlen, simple float mult) =>
    mid   = ta.ema(src, emalen)
    band  = ta.atr(atrlen) * mult
    [mid + band, mid, mid - band]
```

Callers destructure the return:

```pine
[kUpper, kMid, kLower] = vol.keltner(close, 20, 14, 1.5)
```

## Publish and version the library before importing

Libraries must be published (even as private scripts) before they can be imported. The version number in the `import` statement is the major version. Increment the major version when you change function signatures in a breaking way; patch-level changes do not change the import line.

```pine
// To publish: TradingView Editor → Publish → Script library
// The published URL contains the username and script name
```

Import in a consumer script:

```pine
//@version=6
indicator("My Indicator", overlay=true)
import yourUsername/VolUtils/1 as vol

stopDist = vol.atrStop(close, 14, 2.0)
```

The alias (`vol`) scopes all library calls. Use a short alias that matches the library name. Avoid `lib` as a generic alias; it becomes ambiguous when importing multiple libraries.

## Test the library before publishing

Pine has no unit test framework, but you can write a companion indicator that calls every exported function and plots the results:

```pine
//@version=6
indicator("VolUtils Test", overlay=false)
import yourUsername/VolUtils/1 as vol

// Call each function and plot to verify visually
stopDist = vol.atrStop(close, 14, 2.0)
[u, m, l] = vol.keltner(close, 20, 14, 1.5)

plot(stopDist, "Stop dist",   color=color.red)
plot(u,        "Kelt upper",  color=color.blue)
plot(m,        "Kelt mid",    color=color.gray)
plot(l,        "Kelt lower",  color=color.blue)
```

Visual inspection catches obvious errors. Cross-check against known values on a stable instrument (SPY daily, for example) where the ATR is predictable over a specific date range.

## Document every exported function

TradingView renders `// @function`, `// @param`, and `// @returns` annotations in the hover tooltip and in the script's description. Users of your library read these without opening the source.

Write the `// @description` at the top of the file for the library-level summary. Write per-function annotations immediately above each `export` function. See [[coding/pine-script-indicators]] for the user-facing perspective on documentation: the same principle applies here, where the exported API is the contract.

## Related

- [[coding/pine-script]]
- [[coding/pine-script-indicators]]
- [[coding/pine-script-strategies]]
- [[coding/pine-script-security]]
- [[coding/general-principles]]
