Modules

Similar to many other programming languages, Nushell also has modules that let you import custom commands into a current scope. However, since Nushell is also a shell, modules allow you to import environment variables which can be used to conveniently activate/deactivate various environments.

Note! The current implementation of modules is quite bare-bones and will be expanded in the future. For example, it is not yet possible to import a module from within a module.

Basics

A simple module can be defined like this:

  1. > module greetings {
  2. export def hello [name: string] {
  3. $"hello ($name)!"
  4. }
  5. export def hi [where: string] {
  6. $"hi ($where)!"
  7. }
  8. }

or in a file named the same as the the module you want to create:

  1. # greetings.nu
  2. export def hello [name: string] {
  3. $"hello ($name)!"
  4. }
  5. export def hi [where: string] {
  6. $"hi ($where)!"
  7. }

We defined hello and hi custom commands inside a greetings module.

The export keyword makes it possible to later import the commands from the module.

Similar to def, it is also possible to mark def-env with the export keyword (you can learn more about def-env in the Environment chapter).

Using modules

By itself, the module does not do anything. To use what the module exports, we need to use it.

  1. > use greetings
  2. > greetings hello "world"
  3. hello world!
  4. > greetings hi "there"
  5. hi there!

The hello and hi commands are now available with the greetings prefix.

Importing symbols

In general, anything after the use keyword forms an import pattern which controls how the symbols are imported. The import pattern can be one of the following:

use greetings

Imports all symbols with the module name as a prefix (we saw this in the previous example).

use greetings hello

The hello symbol will be imported directly without any prefix.

use greetings [ hello, hi ]

Imports multiple symbols directly without any prefix

use greetings *

You can also use the module name and the * glob to import all names directly without any prefix

Module Files

Nushell lets you implicitly treat a source file as a module. Let’s start by saving the body of the module definition into a file:

  1. # greetings.nu
  2. export def hello [name: string] {
  3. $"hello ($name)!"
  4. }
  5. export def hi [where: string] {
  6. $"hi ($where)!"
  7. }

Now, you can call use directly on the file:

  1. > use greetings.nu
  2. > greetings hello "world"
  3. hello world!
  4. > greetings hi "there"
  5. hi there!

Nushell automatically infers the module’s name from the stem of the file (“greetings” without the “.nu” extension). You can use any import patterns as described above with the file name instead of the module name.

Local Custom Commands

Any custom commands defined in a module without the export keyword will work only in the module’s scope:

  1. # greetings.nu
  2. export def hello [name: string] {
  3. greetings-helper "hello" "world"
  4. }
  5. export def hi [where: string] {
  6. greetings-helper "hi" "there"
  7. }
  8. def greetings-helper [greeting: string, subject: string] {
  9. $"($greeting) ($subject)!"
  10. }

Then, in Nushell we import all definitions from the “greetings.nu”:

  1. > use greetings.nu *
  2. > hello "world"
  3. hello world!
  4. > hi "there"
  5. hi there!
  6. > greetings-helper "foo" "bar" # fails because 'greetings-helper' is not exported

Environment Variables

So far we used modules just to import custom commands. It is possible to export environment variables the same way. The syntax is slightly different than what you might be used to from commands like let-env or load-env:

  1. # greetings.nu
  2. export env MYNAME { "Arthur, King of the Britons" }
  3. export def hello [name: string] {
  4. $"hello ($name)"
  5. }

use works the same way as with custom commands:

  1. > use greetings.nu
  2. > $env."greetings MYNAME"
  3. Arthur, King of the Britons
  4. > greetings hello $env."greetings MYNAME"
  5. hello Arthur, King of the Britons!

You can notice we do not assign the value to MYNAME directly. Instead, we give it a block of code ({ ...}) that gets evaluated every time we call use. We can demonstrate this property, for example, with the random command:

  1. > module roll { export env ROLL { random dice | into string } }
  2. > use roll ROLL
  3. > $env.ROLL
  4. 4
  5. > $env.ROLL
  6. 4
  7. > use roll ROLL
  8. > $env.ROLL
  9. 6
  10. > $env.ROLL
  11. 6

Exporting symbols

As mentioned above, you can export definitions and environment variables from modules. This lets you more easily group related definitions together and export the ones you want to make public.

You can also export aliases and externs, giving you a way to only use these features when you need. Exporting externs also gives you the ability to hide custom completion commands in a module, so they don’t have to be part of the global namespace.

Here’s the full list of ways you can export:

  • export def - export a custom command
  • export def-env - export a custom environment command
  • export env - export an environment variable
  • export alias - export an alias
  • export extern - export a known external definition

Hiding

Any custom command, alias or environment variable, imported from a module or not, can be “hidden”, restoring the previous definition. (Note, it is not yet possible to export aliases from modules but they can still be hidden.) We do this with the hide command:

  1. > def foo [] { "foo" }
  2. > foo
  3. foo
  4. > hide foo
  5. > foo # error! command not found!

The hide command also accepts import patterns, just like use. The import pattern is interpreted slightly differently, though. It can be one of the following:

hide foo or hide greetings

  • If the name is a custom command or an environment variable, hides it directly. Otherwise:
  • If the name is a module name, hides all of its exports prefixed with the module name

hide greetings hello

  • Hides only the prefixed command / environment variable

hide greetings [hello, hi]

  • Hides only the prefixed commands / environment variables

hide greetings *

  • Hides all of the module’s exports, without the prefix

Let’s show these with examples. We saw direct hiding of a custom command already. Let’s try environment variables:

  1. > let-env FOO = "FOO"
  2. > $env.FOO
  3. FOO
  4. > hide FOO
  5. > $env.FOO # error! environment variable not found!

The first case also applies to commands / environment variables brought from a module (using the “greetings.nu” file defined above):

  1. > use greetings.nu *
  2. > $env.MYNAME
  3. Arthur, King of the Britons
  4. > hello "world"
  5. hello world!
  6. > hide MYNAME
  7. > $env.MYNAME # error! environment variable not found!
  8. > hide hello
  9. > hello "world" # error! command not found!

And finally, when the name is the module name (assuming the previous greetings module):

  1. > use greetings.nu
  2. > $env."greetings MYNAME"
  3. Arthur, King of the Britons
  4. > greetings hello "world"
  5. hello world!
  6. > hide greetings
  7. > $env."greetings MYNAME" # error! environment variable not found!
  8. > greetings hello "world" # error! command not found!