Custom CLI Scripts

In this chapter, you'll learn how to create and execute custom scripts from MedusaGo's CLI tool.

What is a Custom CLI Script?#

A custom CLI script is a function that you execute with the exec command of MedusaGo's CLI tool. You use it when you need to run a task once, or occasionally, with access to the application's resources: for example, to seed data, to fix data, or to try something out.

The script receives the container of the application, so it can use the module services, Query, the Link service, and the workflows of the application.


How to Create a Custom CLI Script?#

A script is a function of type ExecScript, from the common package of types. It receives a context and an ExecArgs value with the container and the script's arguments, and it returns an error:

src/scripts/my-script.go
// MyScript logs the number of products. It is registered with the name
// "my-script".
func MyScript(ctx context.Context, args typescommon.ExecArgs) error {
	logger := args.Container.Resolve(common.ContainerRegistrationKeys.LOGGER).(*slog.Logger)
	q := args.Container.Resolve(common.ContainerRegistrationKeys.QUERY).(*query.Query)

	res, err := q.Graph(ctx, query.GraphInput{
		Entity: "product",
		Fields: []string{"id"},
	}, joiner.Options{})
	if err != nil {
		return err
	}

	logger.Info(fmt.Sprintf("Found %d products", len(res.Data)))
	return nil
}

The script above resolves the logger and Query from the container, retrieves the products, and logs how many there are. If it returns an error, the exec command logs it and exits with a non-zero status.

Go can't import a file by its path at run time, as Medusa does. So you register each script by its name in the Scripts option of cli.Run, in the main.go file of your application:

main.go
func main() {
	// Links must be defined before the application is loaded.
	if err := links.Define(); err != nil {
		log.Fatal(err)
	}

	os.Exit(cli.Run(os.Args[1:], cli.Options{
		Config: Config,
		Scripts: map[string]typescommon.ExecScript{
			"my-script": scripts.MyScript,
			"greet":     scripts.Greet,
			"seed":      scripts.Seed,
			"test-blog": scripts.TestBlog,
		},
	}))
}

The key of the map is the name of the script. my-script is the name of the function above.


How to Run a Custom CLI Script?#

To run the script, run the exec command with the script's name, in your application's directory:

Terminal
go run . exec my-script

The command loads the application, without the Medusa Admin, so that the script has everything the application has. It logs Executing script at my-script..., runs the script, which logs the number of products, and logs Finished executing script.

You can also name the script by the path of the file where it would be in a Medusa-style layout, such as go run . exec ./src/scripts/my-script.go. MedusaGo maps the path to the name my-script: it drops the extension, and the src/scripts directory.

If the name isn't registered, the command fails with an error that lists the registered scripts.


Custom CLI Script Arguments#

Your script can accept arguments from the command line. Pass them after the name of the script:

Terminal
go run . exec greet Ada Grace

The arguments are in the Args field of the ExecArgs value, as a list of strings:

src/scripts/greet.go
// Greet logs the arguments that follow the script name:
// `go run . exec greet Ada Grace`.
func Greet(ctx context.Context, args typescommon.ExecArgs) error {
	logger := args.Container.Resolve(common.ContainerRegistrationKeys.LOGGER).(*slog.Logger)
	for _, name := range args.Args {
		logger.Info("Hello, " + name)
	}
	return nil
}

A script loads the application like the other commands do. Define your module links before you call cli.Run, as the main function above does, so that the script can use them in Query and in the Link service.

The Seed Data chapter shows a script that uses the services of a module, a workflow, and links.

Found a problem with this page?Report Issue
Edited Nov 14·Edit this page