---
url: https://node-ts.github.io/bus/guide/messages/commands.md
description: >-
  Declare, send and handle commands, which instruct a single service to do some
  work.
---

# Commands

A command is a message that instructs a service to do some work. It could be a technical instruction, such as `BackupDatabase`, or modelled on your business, such as `PlaceOrder` or `ShipPackage`. This page covers declaring, sending and handling commands.

::: tip
Name commands in plain English, as an instruction. It makes it clear what will happen when the command is handled.
:::

## Declaring a command

A command is a class that extends `Command`:

```ts
import { Command } from '@node-ts/bus-messages'

export class ChargeCreditCard extends Command {
  /**
   * A unique name that identifies the message, in a namespace style such as
   * organisation/domain/command-name. The bus routes messages by this name.
   */
  static NAME = 'my-app/accounts/charge-credit-card'
  $name = ChargeCreditCard.NAME

  /**
   * The contract version of this message. Increment it when the message's
   * fields change in a way that isn't backwards compatible.
   */
  $version = 1

  /**
   * Create a charge on a credit card
   * @param creditCardToken Identifies the card to charge
   * @param amount The amount, in USD, to charge the card
   */
  constructor(
    readonly creditCardToken: string,
    readonly amount: number
  ) {
    super()
  }
}

```

## Sending a command

A command is handled by a single service, unlike an event, which can have many subscribers. The service usually handles the command, and then publishes an [event](/guide/messages/events) to say it's done. Send a command with `send()`, optionally with [attributes](/guide/message-attributes):

```ts
const chargeCreditCard = new ChargeCreditCard('tok_visa', 1200)

// Send a command. It's handled by a single service
await bus.send(chargeCreditCard)

// Send a command with attributes
await bus.send(chargeCreditCard, {
  correlationId: 'cd091b26-f0e6-43fb-9962-c06786948e26'
})
```

## Handling a command

Commands are handled by a function declared with `handlerFor`, or a class that implements `Handler`. Both get the message, its attributes and a [`HandlerContext`](/api/bus-core/interfaces/HandlerContext). Events published through the context are held until the handler resolves, and dropped if it throws, so a failed command doesn't announce that it succeeded.

::: code-group

```ts \[Function]
export const chargeCreditCardHandler = handlerFor(
  ChargeCreditCard,
  async (command, _attributes, ctx) => {
    await paymentService.charge(command.creditCardToken, command.amount)
    await ctx.publish(
      new CreditCardCharged(command.creditCardToken, command.amount, new Date())
    )
  }
)
```

```ts \[Class]
export class ChargeCreditCardHandler implements Handler<ChargeCreditCard> {
  // A getter, so the bus can read it without constructing the handler
  get messageType() {
    return ChargeCreditCard
  }

  async handle(
    command: ChargeCreditCard,
    _attributes: MessageAttributes,
    ctx: HandlerContext
  ) {
    await paymentService.charge(command.creditCardToken, command.amount)
    await ctx.publish(
      new CreditCardCharged(command.creditCardToken, command.amount, new Date())
    )
  }
}
```

:::

Register the handler with the bus configuration, then start the bus to begin handling messages:

```ts
const paymentsBus = Bus.configure()
  .withMessageTypes(messageTypes)
  .withHandler(chargeCreditCardHandler) // Function handler
  .build()

await paymentsBus.initialize()
// Start the bus to begin handling messages
await paymentsBus.start()
```

## See also

* [Events](/guide/messages/events)
* [Retry strategies](/guide/retry-strategies), for what happens when a handler throws
* [Dependency injection](/guide/dependency-injection), for class handlers with dependencies
