# @poppinss/macroable

> Extend classes from outside in using Macros and getters

Latest version **1.1.2** (published 2026-03-18) · MIT license · 0 weekly downloads

## Install

```sh
npm install @poppinss/macroable
pnpm add @poppinss/macroable
yarn add @poppinss/macroable
bun add @poppinss/macroable
```

## Health

**Score 65/100 (B)** — status: stable.

Positive: has types; esm support; no vulnerabilities; has provenance; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 1.1.2 |
| Published | 2026-03-18 |
| First published | 2022-10-14 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 0 |
| Unpacked size | 16 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| GitHub stars | 40 |
| Author | virk,poppinss |
| Maintainers | virk, romainlanz, julien-r44 |
| Keywords | macroable |

## Links

- npm: https://www.npmjs.com/package/@poppinss/macroable
- Repository: https://github.com/poppinss/macroable
- Homepage: https://github.com/poppinss/macroable#readme
- Issues: https://github.com/poppinss/macroable/issues
- npm.io page: https://npm.io/package/@poppinss/macroable

## Recent versions

- 1.1.2 (latest) — 2026-03-18
- 1.0.0-8 (next) — 2023-09-23
- 1.1.1 — 2026-03-09
- 1.1.0 — 2025-09-11
- 1.0.5 — 2025-07-04
- 1.0.4 — 2024-12-27
- 1.0.3 — 2024-09-17
- 1.0.2 — 2024-03-28
- 1.0.1 — 2023-12-15
- 1.0.0 — 2023-10-14
- 1.0.0-7 — 2023-06-29
- 1.0.0-6 — 2023-04-17
- 1.0.0-5 — 2023-04-15
- 1.0.0-4 — 2023-03-25
- 1.0.0-3 — 2023-03-11
- … 3 more at https://npm.io/package/@poppinss/macroable/versions

## README

# @poppinss/macroable
> Extend classes from outside in using Macros and getters

[![gh-workflow-image]][gh-workflow-url] [![typescript-image]][typescript-url] [![npm-image]][npm-url] [![license-image]][license-url]

Macroable offers a simple API for adding properties and getters to the class prototype. You might not even need this package, if you are happy writing `Object.defineProperty` calls yourself.

## Usage
Install the package from npm packages registry as follows.

```sh
npm i @poppinss/macroable

# yarn lovers
yarn add @poppinss/macroable
```

And import the `Macroable` class.

```ts
import Macroable from '@poppinss/macroable'
export class Route extends Macroable {}
```

Now, you can add properties to the Route class from outside-in. This is usually needed, when you want the consumer of your classes to be able to extend them by adding custom properties.

## Macros
Getters are added to the class prototype directly.

```ts
Route.macro('head', function (uri, callback) {
  return this.route(['HEAD'], uri, callback)
})
```

And now, you can will be use the `head` method from an instance of the `Route` class.

```ts
const route = new Route()
route.head('/', () => {})
```

Adding a macro is same as writing the following code in JavaScript.

```ts
Route.prototype.head = function () {
}
```

## Instance properties
Since, macros are defined on the prototype of the class and therefore they loose the `this` context when destructured from the class instance. For example:

```ts
HttpContext.macro('getUser', function (this: HttpContext) {
  return this.auth.user
})

const { getUser } = ctx
getUser() // ❌ Error: Cannot read property auth of undefined
```

In order to fix this issue, the properties that can be destructured must be defined as instance properties on the class.

```ts
HttpContext.instanceProperty('getUser', function (this: HttpContext) {
  return this.auth.user
})

const { getUser } = ctx
getUser() // ✅ Works fine
```

## Getters
Getters are added to the class prototype using the `Object.defineProperty`. The implementation of a getter is always a function.

```ts
Route.getter('version', function () {
  return 'v1'
})
```

And now access the version as follows.

```ts
const route = new Route()
route.version // v1
```

Adding a getter is same as writing the following code in JavaScript.

```ts
Object.defineProperty(Route.prototype, 'version', {
  get() {
    const value = callback()
    return value
  },
  configurable: false,
  enumerable: false,
})
```

## Singleton getters
Singleton getters are also defined on the class prototype. However, their values are cached after the first access.

```ts
const singleton = true

Mysql.getter('version', function () {
  return this.config.driver.split('-')[1]
}, singleton)
```

Adding a singleton getter is same as writing the following code in JavaScript.

```ts
Object.defineProperty(Mysql.prototype, 'version', {
  get() {
    const value = callback()

    // Cache value on the class instance
    Object.defineProperty(this, 'version', {
      configurable: false,
      enumerable: false,
      value: value,
      writable: false,
    })

    return value
  },
  configurable: false,
  enumerable: false,
})
```

## TypeScript types
You will have to use [module augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation) in order to define the types for the dynamically added properties.

## Contributing

One of our primary goals is to have a vibrant community of users and contributors who believes in the principles of the framework.

We encourage you to read the [contribution guide](https://github.com/poppinss/.github/blob/main/docs/CONTRIBUTING.md) before contributing to the framework.

## Code of Conduct

In order to ensure that the community is welcoming to all, please review and abide by the [Code of Conduct](https://github.com/poppinss/.github/blob/main/docs/CODE_OF_CONDUCT.md).

## License

Poppinss macroable is open-sourced software licensed under the [MIT license](LICENSE.md).

[gh-workflow-image]: https://img.shields.io/github/actions/workflow/status/poppinss/macroable/checks.yml?style=for-the-badge
[gh-workflow-url]: https://github.com/poppinss/macroable/actions/workflows/checks.yml "Github action"

[typescript-image]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript
[typescript-url]: "typescript"

[npm-image]: https://img.shields.io/npm/v/@poppinss/macroable.svg?style=for-the-badge&logo=npm
[npm-url]: https://npmjs.org/package/@poppinss/macroable 'npm'

[license-image]: https://img.shields.io/npm/l/@poppinss/macroable?color=blueviolet&style=for-the-badge
[license-url]: LICENSE.md 'license'

---
_Source: https://npm.io/package/@poppinss/macroable · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
