export const meta = {
title: `Command Hooks`,
description: `Execute custom scripts before, during, and after Amplify CLI commands (“amplify push”, “amplify api gql-compile”, and more).`,
};
Use Command Hooks to execute custom scripts before, during, and after Amplify CLI commands (“amplify push”, “amplify api gql-compile”, and more). This allows you to extend Amplify’s best-practice defaults to meet your organization’s specific security guidelines and operational requirements.
## Adding a command hook
Hooks need to be checked into source control in order to be made available across machines. `amplify pull` will not re-create the hooks folder automatically as these are considered changes that need to be committed to the repository.
Place your custom scripts in the `amplify/hooks` directory and set the script file name to the desired command with a pre or post designation. For example `post-add-function.js` will execute the script after `amplify add function`. For more information about the script naming convention, see [How to name command hook scripts](#how-to-name-command-hook-scripts).
For this example, let's create a hook to ensure that a minimum major Amplify CLI version is used before deployment (`amplify push`).
Let's add `pre-push.js` in the `amplify/hooks` directory with the following contents. *Note: You need to create a `amplify/hooks` folder if your Amplify project was created prior to Amplify CLI version 5.5.0*
```js
const fs = require('fs');
const parameters = JSON.parse(fs.readFileSync(0, { encoding: 'utf8' }));
// Get the running Amplify CLI major version number
const currentCLIMajorVersion = parameters.data.amplify.version.split('.')[0]
console.log('Amplify CLI major version: ', currentCLIMajorVersion)
const MINIMUM_MAJOR_AMPLIFY_CLI_VERSION = 5
console.log('Minimum required Amplify CLI major version: ', MINIMUM_MAJOR_AMPLIFY_CLI_VERSION)
if (currentCLIMajorVersion < MINIMUM_MAJOR_AMPLIFY_CLI_VERSION) {
// Non-zero exit code will stop the Amplify CLI command's execution
console.log('Minimum CLI version requirement not met.')
process.exit(1)
} else {
console.log('Minimum CLI version requirement met.')
process.exit(0)
}
```
Next, let's run `amplify push`:
```bash
amplify push
```
```console
----- 🪝 pre-push execution start -----
Amplify CLI major version: 5
Minimum required Amplify CLI major version: 5
Minimum CLI version requirement met.
----- 🪝 pre-push execution end -----
```
## How to name command hook scripts
To hook into a command, the script file in the `amplify/hooks` directory should be named with the following naming convention:
`pre|post-[-].extension`
- `command` (required) - Amplify command.
- `extension` (required) - by default `.js` and `.sh` are mapped to Node.js and Bash. To support more extensions or scripting runtimes, see [Adding a custom scripting runtime](#adding-a-custom-scripting-runtime).
- `sub-command` (optional) - Amplify sub-command. Can be used to increase hook specificity. Example: `pre-add-auth` and `pre-mock-api`.
The following is an exhaustive list of all commands along with their subcommands that are supported by Amplify CLI:
commands | sub-commands **(optional)**
------------------------|------------------------
`add` |all categories (`api`, `auth`, etc.)
`codegen`
`env`
`update` |all categories (`api`, `auth`, etc.)
`env`
`remove` |all categories (`api`, `auth`, etc.)
`env`
`push` |`analytics`, `api`, `auth`, `function`, `hosting`, `interactions`, `storage`, `xr`
`pull` |`env`
`publish` |-
`delete` |-
`checkout` |`env`
`list` |`env`
`get` |`env`
`mock` |`api`, `storage`, `function`
`build` |`function`
`status` |`notifications`
`import` |`auth`, `storage`, `env`
`gqlcompile` |`api`
`addgraphqldatasource` |`api`
`statements` |`codegen`
`types` |`codegen`
*Note: Multiple hook scripts with the same filename are not allowed*
## Access parameters in hook scripts
Command hooks receive two parameters, `data` and `error`. Amplify CLI passes parameters to hook scripts as a JSON string through standard input.
### **data** parameter structure
```json
{
"amplify": {
"version": String,
"environment": {
"envName": String,
"projectPath": String,
"defaultEditor": String
},
"command": String,
"subCommand": String,
"argv": [ String ]
}
}
```
- amplify
- version - current Amplify CLI version
- environment - current Amplify environment
- envName - current Amplify environment name
- projectPath - path to current Amplify project
- defaultEditor - chosen editor in init step. Example `vscode`
- command - hooked Amplify CLI command. Example: `push`
- subCommand - hooked Amplify CLI subcommand or plugin. Example `auth`, `env`.
- argv - list containing the arguments passed to Amplify CLI through the command line
### **error** parameter structure
**error** is `undefined` if no error is emitted. Otherwise, it has the following structure:
```json
{
"message": String,
"stack": String
}
```
- message - the error message emitted by Amplify CLI
- stack - the error stack emitted by Amplify CLI
### How to access command hook parameters in Node.js
```javascript
const fs = require('fs');
const parameters = JSON.parse(fs.readFileSync(0, { encoding: 'utf8' }));
console.log(parameters.data, parameters.error)
```
### How to access command hook parameters in Bash
First, install a JSON parser like [`jq`](https://stedolan.github.io/jq/download/).
Then, parse the parameters:
```bash
parameters=`cat`
data=$(jq -r '.data' <<< "$parameters")
error=$(jq -r '.error // empty' <<< "$parameters")
echo $data
echo $error
```
## How to conditionally stop an Amplify CLI command execution
To stop the execution of Amplify CLI, the hook scripts can exit with a non-zero exit code.
```js
process.exit(1)
```
```bash
exit 1
```
## Advanced command hook configurations
You can optionally add `hooks-config.json` in `amplify/hooks` to configure custom scripting runtimes or manage external dependencies.
### Adding a custom scripting runtime
By default, Node.js and Bash are supported. To support additional runtimes, add `extensions` to the `hooks-config.json` file in the `amplify/hooks` folder.
An example showcasing python runtime support and different runtime settings based on operating system:
```json
{
"extensions": {
"py": {
"runtime": "python3"
},
"js": {
"runtime": "~/.nvm/versions/node/v14.17.1/bin/node",
"runtime_windows": "node",
"runtime_options": ["--require", "./payload.js"],
}
}
}
```
- The keys in the `extensions` ( js, py ) are values that will be used as `extension` in the [naming convention](#how-to-name-command-hook-scripts) used when naming the hook scripts.
- `runtime` (required) - symlink (`node`, `python`, `bash`) or path to executable (`~/.nvm/versions/node/v14.17.1/bin/node`).
- `runtime_windows` (optional) - windows specific symlink or path to executable.
- `runtime_options` (optional) - Array of cli options to be passed to command hooks specific to runtime.
### Managing third-party dependencies
Packages from external package managers like `npm` can be used in command hooks scripts. In this example, you'll install `axios` as a dependency for your Node.js hooks.
First, go to the hooks folder and install the `axios` dependency.
```bash
cd amplify/hooks
npm init
npm install axios
```
*Note*: If you use command hooks with Amplify Hosting CI/CD pipelines, you also need to have a `preBuild` step configured to install the hook dependencies:
```yaml
backend:
phases:
preBuild:
commands:
- cd amplify/hooks
- npm install
frontend:
...
```
Dependency directories and files, such as `node_modules`, should be added to `ignore` in `hooks-config.json`.
```json
{
"ignore": ["node_modules", "build"]
}
```
*Note*: All entries in `ignore` should follow the [.gitignore specification](http://git-scm.com/docs/gitignore).
You can now use `axios` in your hook scripts placed in the `amplify/hooks` directory.
### Executing different logic based on environment
When using multi-environment setup you can customize command hooks logic based on `data.amplify.environment.envName` parameter.
```javascript
/**
* @param data { { amplify: { environment: { envName: string, projectPath: string, defaultEditor: string }, command: string, subCommand: string, argv: string[] } } }
* @param error { { message: string, stack: string } }
*/
const hookHandler = async (data, error) => {
if (data.amplify.environment.envName === 'prod') {
console.log('Executing pre-add-auth hook for prod environment');
} else if (data.amplify.environment.envName === 'dev') {
console.log('Executing pre-add-auth hook for dev environment');
}
};
const getParameters = async () => {
const fs = require("fs");
return JSON.parse(fs.readFileSync(0, { encoding: "utf8" }));
};
getParameters()
.then((event) => hookHandler(event.data, event.error))
.catch((err) => {
console.error(err);
process.exitCode = 1;
});
```
## Using command hooks in Amplify's CI/CD pipeline
Command hooks are executed when [CI/CD builds are triggered on Amplify Hosting](https://docs.aws.amazon.com/amplify/latest/userguide/multi-environments.html). To execute hook scripts in the Amplify Hosting, add the hook scripts to the `amplify/hooks` directory and commit them to your source control.
By default only `pre-push` and `post-push` hooks will be executed on builds in Amplify Hosting.
To use scripting runtimes other than Node.js and Bash, see [Adding a custom scripting runtime](#adding-a-custom-scripting-runtime) and also update the **Build Settings** in Amplify Hosting to include the runtime executable.
In this example, you'll add a `python` hook script running in the Amplify Hosting's CI/CD pipeline:
1. Add the python hook script along with `hooks-config.json` to the hooks directory.
```bash
touch amplify/hooks/hooks-config.json
```
2. Navigate to your app in the Amplify Hosting and select **App settings** > **Build settings** to update the `preBuild` phase to install python.
```yaml
...
backend:
phases:
preBuild:
commands:
- yum install -y python3
frontend:
...
```
3. Add `python3` to `hooks-config.json` and push the change to your source control to trigger the Amplify Hosting build.
```json
{
"extensions": {
"py": { "runtime": "python3" }
}
}
```
4. You’re all set! The python command hooks will be executed in new CI/CD builds.
## Command hook limitations with Amplify Studio
Command Hooks are not executed when updating a backend via Amplify Studio.