Prerequisites
- Web console
- CLI
- Go SDK
- Python SDK
- JavaScript SDK
Make sure you are in a group that has at least the
editor role within your tenant or project; for example, the default editors group. You can check this in the Administration → IAM section of the web console.To open Devlabs and check logs, you need at least the viewer role.-
Install and configure the Nebius AI Cloud CLI.
Check that your project ID is saved in the Nebius AI Cloud CLI profile configuration:
cat ~/.nebius/config.yaml -
Make sure you are in a group that has at least the
editorrole within your tenant or project; for example, the defaulteditorsgroup. You can check this in the Administration → IAM section of the web console. To open Devlabs and check logs, you need at least theviewerrole.
- Install and initialize the Nebius SDK for Go.
-
Make sure you are in a group that has at least the
editorrole within your tenant or project; for example, the defaulteditorsgroup. You can check this in the Administration → IAM section of the web console. To open Devlabs and check logs, you need at least theviewerrole.
- Install and initialize the Nebius SDK for Python.
-
Make sure you are in a group that has at least the
editorrole within your tenant or project; for example, the defaulteditorsgroup. You can check this in the Administration → IAM section of the web console. To open Devlabs and check logs, you need at least theviewerrole.
- Install and initialize the Nebius SDK for JavaScript.
-
Make sure you are in a group that has at least the
editorrole within your tenant or project; for example, the defaulteditorsgroup. You can check this in the Administration → IAM section of the web console. To open Devlabs and check logs, you need at least theviewerrole.
How to create a Devlab
To create an interactive development environment, create a Devlab:- Web console
- CLI
- Go SDK
- Python SDK
- JavaScript SDK
If you want to create a Devlab based on an existing one, find the Devlab on the Serverless AI → Devlabs page and click
→ Clone. On the creation page that opens, review the prefilled settings, modify them if needed, and click Create Devlab.
-
In the sidebar, go to
Serverless AI → Devlabs.
-
Click
Create Devlab.
- Specify the Devlab name.
-
Configure Devlab settings:
- Select Custom to provide your own container image, or Template to start from a template.
- If you selected Custom, in Image path, set the path to the container image.
-
If you use a private registry, click
Add registry and provide the details for your registry.
- In Ports, set the container ports for the Devlab. For each port, select HTTP or TCP. You can add multiple ports. The primary web UI port gets the Devlab’s managed HTTPS URL; other ports are shown in the Devlab status but aren’t publicly routed.
- (Optional) In Entrypoint command, specify the entrypoint command for the container. If you need to pass container arguments, specify them in this field as well.
- (Optional) In Environment variables, specify environment variables in key-value pairs.
-
(Optional) In Secret environment variables, click
Create secret to store a sensitive value in SecretStash and inject it as an environment variable. In the window that opens, specify the Key (environment variable name) and Value (secret data), then click Create.
-
(Optional) Enable Bearer token authentication if you want to protect the Devlab web UI with a token.
- Under Token, click
Create.
- In the Create secret with token window, specify the secret Name and, optionally, a Description.
- In Token, enter a token or click Generate. Copy and save the token securely before proceeding. The token is saved as the first value in a SecretStash secret.
- Click Create secret.
- Under Token, click
- (Optional) In Platform, select With GPUs or Without GPUs, then select the platform.
- (Optional) In Settings, select the preset. The preset must match the selected platform.
-
(Optional) Configure Storage settings:
-
Under Container disk size, specify at least 50 GiB for GPU workloads or 20 GiB for CPU-only workloads. If the container image requires a bigger disk size, set at least the minimum required value for the image. Otherwise, the workloads won’t be able to launch. For more information, see how disk performance depends on disk size.
Data under the workspace path on this disk persists across stop and restart. The workspace is a path on the container disk (
/workspaceby default, or the path declared by the template). Its size is limited only by the disk size. While the Devlab is stopped, the entire container disk continues to be billed. - Under Mounted volumes, click Attach volume to attach a bucket or a filesystem. You can create a bucket or filesystem, or use an existing one. To create a new bucket, see Bucket parameters. To create a new filesystem, see Volume parameters.
-
Under Container disk size, specify at least 50 GiB for GPU workloads or 20 GiB for CPU-only workloads. If the container image requires a bigger disk size, set at least the minimum required value for the image. Otherwise, the workloads won’t be able to launch. For more information, see how disk performance depends on disk size.
Data under the workspace path on this disk persists across stop and restart. The workspace is a path on the container disk (
- (Optional) In Files, upload files or create text files to inject into the container. The maximum file size is 64 KB.
-
Configure the Network section:
- Select a network and a subnet, or create a new subnet.
- Select the IP address type: Auto dynamic IP or Private IP. A public IP address isn’t required to open the Devlab web UI over the managed HTTPS URL. If you add an SSH key, make sure that network access allows SSH so you can connect to the VM.
- Click Create Devlab.
-
If you want to create a Devlab from a template, list the available templates and choose one:
nebius ai devlab template list -
Create the Devlab. Use either a template or a container image:
-
From a template:
nebius ai devlab create \ --name <devlab_name> \ --template <template> \ --input <key>=<value> \ --env <key>=<value> \ --env-secret <key>=<secret_selector> \ --container-port <port> \ --workspace-path <absolute_path> \ --volume <source:container_path[:mode]|s3://bucket:/container_path[:mode[:profile]]> \ --inject-file "<local_path>:<absolute_container_path>" \ --platform <platform_ID> \ --preset <preset> \ --disk-size <size> \ --shm-size <size> \ --subnet-id <subnet_ID> \ --ssh-key <SSH_public_key> \ --public
Example: Create a Devlab from the JupyterLab template
Provide your own random Jupyter token asnebius ai devlab create \ --name my-jupyter \ --template jupyter \ --input jupyter_token=A1b2C3d4E5f6G7h8--input jupyter_token=<token>. The token must contain exactly 16 alphanumeric characters. For example, you can generate one withopenssl rand -hex 8.-
From a container image:
nebius ai devlab create \ --name <devlab_name> \ --image <image> \ --registry-secret <secret_selector> \ --container-command "<command>" \ --args "<arguments>" \ --working-dir <absolute_path> \ --primary-route-port <port> \ --env <key>=<value> \ --env-secret <key>=<secret_selector> \ --container-port <port> \ --workspace-path <absolute_path> \ --volume <source:container_path[:mode]|s3://bucket:/container_path[:mode[:profile]]> \ --inject-file "<local_path>:<absolute_container_path>" \ --platform <platform_ID> \ --preset <preset> \ --disk-size <size> \ --shm-size <size> \ --subnet-id <subnet_ID> \ --ssh-key <SSH_public_key> \ --public
Example: Create a Devlab from a container image
nebius ai devlab create \ --name nginx-devlab \ --image docker.io/library/nginx:1.27-alpine \ --platform cpu-e2 \ --primary-route-port 80 -
From a template:
-
Devlab settings:
-
--name: Devlab name. -
--templateor--image: How to define the container. Specify one of these parameters:--template: Template to use, for example,jupyter. Mutually exclusive with--image. The template declares the container image, entrypoint command, arguments, working directory, ports, primary web route, and the default workspace path. Don’t set--image,--container-command,--args,--working-dir, or--primary-route-portwith--template. To see available templates, runnebius ai devlab template list.--image: Container image reference in theregistry/path:tagorregistry/path@digestformat. Mutually exclusive with--template. Required unless you set--template.
-
--input(optional for some templates; required for JupyterLab): Template input in thekey=valueformat. Requires--template. To set several inputs, repeat the parameter. For the JupyterLab template, set--input jupyter_token=<token>, where<token>is a random string of exactly 16 alphanumeric characters that you provide. -
--registry-secret(optional): SecretStash secret selector withREGISTRY_USERNAMEandREGISTRY_PASSWORDpayload keys. You can specify a secret name, secret ID, version ID or a combined secret/version selector such asmbsec-e00***@mbsecver-e00***. Use when you pull an image from a private registry. Applies only with--image. -
--container-command(optional): Entrypoint command for the container. Applies only with--image. Declared by the template when you use--template. -
--args(optional): Arguments for the entrypoint command. Applies only with--image. Declared by the template when you use--template. -
--working-dir(optional): Working directory (absolute path). Applies only with--image. Declared by the template when you use--template. -
--primary-route-port: Container port for the primary web UI behind the managed HTTPS URL. Required with--image. Declared by the template when you use--template. Must match an HTTP port from--container-port. -
--env(optional): Environment variables for the container in thekey=valueformat. To set several variables, repeat the parameter. With--template, these variables extend the template-declared ones. -
--env-secret(optional): Environment variables loaded from a SecretStash secret in thekey=secret_selectorformat. The value can be a secret name, secret ID, version ID or a combined secret/version selector such asmbsec-e00***@mbsecver-e00***. To set several variables, repeat the parameter. -
--container-port(optional): Port to expose from the container, for example,8080/httpor9000/tcp. Supported protocols arehttp,tcp, andudp. To expose several ports, repeat the parameter. With--template, these ports extend the template-declared ones. Additional ports appear in the Devlab status but aren’t publicly routed unless they are the primary web route. -
--workspace-path(optional): Absolute path of the workspace on the container disk. Data under this path persists across stop and restart. The default is/workspace. With--template, the template can declare a different path. You can set this path in the CLI or API; the web console does not expose it. The path must not overlap mounted volume paths. The workspace size is limited only by the container disk size (--disk-size). -
--volume(optional): Bucket or shared filesystem to mount to the Devlab container. Volume mount paths must not overlap the workspace path. Specify the value in either format:source:container_path[:mode]for mounting Nebius shared filesystems and existing bucket or volume resources by ID or name.s3://bucket:/container_path[:mode[:profile]]for mounting an Object Storage bucket with AWS profile credentials or S3 credentials stored in SecretStash. Theprofileis the AWS credentials profile to use. If you manage your credentials with SecretStash, useprofile@<secret_selector>, where<secret_selector>is a secret name, secret ID, version ID or a combined secret/version selector such asmbsec-e00***@mbsecver-e00***
ro, read only, andrw, read-write (default). Repeat for multiple volumes. For example:--volume 'computefilesystem-e***:/input:ro' \ --volume 'storagebucket-e***:/output:rw' \ --volume 's3://training-results:/output:rw:default' -
--inject-file(optional): Mount a local file into the Devlab container at launch. Use the format<local_path>:<absolute_container_path>. To inject multiple files, repeat the parameter. The mounted file is read-only and limited to 64 KiB.
-
-
Underlying VM characteristics:
-
--platform(optional): VM platform. If you omit the parameter, the CLI selects the default GPU platform. For CPU-only templates, such as Open WebUI, specify a CPU platform explicitly. See available platforms in Types of virtual machines and GPUs in Nebius AI Cloud. -
--preset(optional): Number of GPUs, vCPUs, and RAM allocated to the container. If you omit the parameter, the CLI selects the smallest suitable preset for the platform. The preset must match the selected platform. See available presets in Presets for GPU platforms. -
--disk-size(optional): Disk size of the underlying VM, for example,100Gi,500Gi, or1Ti. If you omit the parameter, the default value250Giapplies. Set at least 50 GiB for GPU workloads or 20 GiB for CPU-only workloads. If the container image requires a bigger disk size, set at least the minimum required value for the image. Otherwise, the workloads won’t be able to launch. For more information, see how disk performance depends on disk size. -
--shm-size(optional): Shared memory size of/dev/shm, for example,64Mi,128Mior1Gi. With--template, you can set this only when the template leaves shared memory unset. -
--subnet-id: Subnet ID for the Devlab. Required if the project has multiple subnets. -
--ssh-key(optional): SSH public key to access the underlying VM by SSH. When you add an SSH key, a public dynamic IP address is assigned. Before you add the key, check the quota on the number of public IP addresses in the web console. -
--public(optional): Assigns a public IP address to the underlying VM. Not required to open the Devlab web UI over the managed HTTPS URL.
-
-
If you want to create a Devlab from a template, list the templates and copy the required template’s
Metadata.Id:listTemplateService := sdk.Services().Applications(). V1Alpha1().VmAppTemplate() listTemplatesRequest := &apps.ListVmAppTemplatesRequest{ GlobalOnly: true, Kind: "devlab", } for { templates, err := listTemplateService.List( ctx, listTemplatesRequest, ) if err != nil { return fmt.Errorf("list devlab templates: %w", err) } fmt.Println(templates) if templates.GetNextPageToken() == "" { break } listTemplatesRequest.PageToken = templates.GetNextPageToken() } -
Create the Devlab. Use either a template or a container image:
-
From a template:
templateFile, err := os.ReadFile("<local_path>") if err != nil { return fmt.Errorf("read injected file: %w", err) } templateSpec := &ai.DevlabSpec{ Template: &ai.DevlabSpec_Template{ Id: "<template_ID>", InputFieldValues: map[string]*structpb.Value{ "jupyter_token": structpb.NewStringValue( "<jupyter_token>", ), }, }, EnvironmentVariables: []*ai.DevlabSpec_EnvironmentVariable{ { Name: "DEVLAB_ENV", ValueSource: &ai.DevlabSpec_EnvironmentVariable_Value{ Value: "<value>", }, }, }, Ports: []*ai.DevlabSpec_Port{ { ContainerPort: <port>, Protocol: ai.DevlabSpec_Port_HTTP, }, }, Volumes: []*ai.DevlabSpec_VolumeMount{ { Source: "<bucket_ID>", ContainerPath: "<container_path>", Mode: ai.DevlabSpec_VolumeMount_READ_WRITE, }, }, InjectedFiles: []*ai.DevlabSpec_FileInjection{ { ContainerPath: "<absolute_container_path>", Content: templateFile, }, }, SshAuthorizedKeys: []string{ "<SSH_public_key>", }, PublicIp: true, Platform: "<platform_ID>", Preset: "<preset>", Disk: &ai.DevlabSpec_DiskSpec{ Type: compute.DiskSpec_NETWORK_SSD, SizeBytes: <disk_size_in_bytes>, }, Workspace: &ai.DevlabSpec_Workspace{ ContainerPath: "<absolute_path>", }, SubnetId: "<subnet_ID>", } templateSecretID := "<secret_ID>" if templateSecretID != "" { templateSecret := &ai.DevlabSpec_EnvironmentVariable_MysteryboxSecret{ MysteryboxSecret: &ai.DevlabSpec_MysteryBoxSecretRef{ SecretId: templateSecretID, }, } templateSpec.EnvironmentVariables = append( templateSpec.EnvironmentVariables, &ai.DevlabSpec_EnvironmentVariable{ Name: "DEVLAB_SECRET", ValueSource: templateSecret, }, ) } templateService := sdk.Services().Ai().V1().Devlab() templateOperation, err := templateService.Create( ctx, &ai.CreateDevlabRequest{ Metadata: &common.ResourceMetadata{ ParentId: "<project_ID>", Name: "<devlab_name>", }, Spec: templateSpec, }, ) if err != nil { return fmt.Errorf("create devlab: %w", err) } if _, err = templateOperation.Wait(ctx); err != nil { return fmt.Errorf("wait for devlab creation: %w", err) }Example: Create a Devlab from the JupyterLab template
Replace the sample Jupyter token with your own random token of exactly 16 alphanumeric characters. Save the token securely to sign in to JupyterLab.jupyterSpec := &ai.DevlabSpec{ Template: &ai.DevlabSpec_Template{ Id: "vmapptemplate-g00devlab-jupyter", InputFieldValues: map[string]*structpb.Value{ "jupyter_token": structpb.NewStringValue( "A1b2C3d4E5f6G7h8", ), }, }, Platform: "<platform_ID>", Preset: "<preset>", Disk: &ai.DevlabSpec_DiskSpec{ Type: compute.DiskSpec_NETWORK_SSD, SizeBytes: 268435456000, }, Workspace: &ai.DevlabSpec_Workspace{}, SubnetId: "<subnet_ID>", } jupyterService := sdk.Services().Ai().V1().Devlab() jupyterOperation, err := jupyterService.Create( ctx, &ai.CreateDevlabRequest{ Metadata: &common.ResourceMetadata{ ParentId: "<project_ID>", Name: "my-jupyter", }, Spec: jupyterSpec, }, ) if err != nil { return fmt.Errorf("create devlab: %w", err) } if _, err = jupyterOperation.Wait(ctx); err != nil { return fmt.Errorf("wait for devlab creation: %w", err) } -
From a container image:
imageFile, err := os.ReadFile("<local_path>") if err != nil { return fmt.Errorf("read injected file: %w", err) } imageSpec := &ai.DevlabSpec{ Image: "<image>", PrimaryRoute: &ai.DevlabSpec_PrimaryRoute{ ContainerPort: <port>, }, Ports: []*ai.DevlabSpec_Port{ { ContainerPort: <port>, Protocol: ai.DevlabSpec_Port_HTTP, }, }, ContainerCommand: "<command>", Args: "<arguments>", WorkingDir: "<absolute_path>", ShmSizeBytes: <shared_memory_size_in_bytes>, EnvironmentVariables: []*ai.DevlabSpec_EnvironmentVariable{ { Name: "DEVLAB_ENV", ValueSource: &ai.DevlabSpec_EnvironmentVariable_Value{ Value: "<value>", }, }, }, Volumes: []*ai.DevlabSpec_VolumeMount{ { Source: "<bucket_ID>", ContainerPath: "<container_path>", Mode: ai.DevlabSpec_VolumeMount_READ_WRITE, }, }, InjectedFiles: []*ai.DevlabSpec_FileInjection{ { ContainerPath: "<absolute_container_path>", Content: imageFile, }, }, SshAuthorizedKeys: []string{ "<SSH_public_key>", }, PublicIp: true, Platform: "<platform_ID>", Preset: "<preset>", Disk: &ai.DevlabSpec_DiskSpec{ Type: compute.DiskSpec_NETWORK_SSD, SizeBytes: <disk_size_in_bytes>, }, Workspace: &ai.DevlabSpec_Workspace{ ContainerPath: "<absolute_path>", }, SubnetId: "<subnet_ID>", } imageSecretID := "<secret_ID>" if imageSecretID != "" { imageSecret := &ai.DevlabSpec_EnvironmentVariable_MysteryboxSecret{ MysteryboxSecret: &ai.DevlabSpec_MysteryBoxSecretRef{ SecretId: imageSecretID, }, } imageSpec.EnvironmentVariables = append( imageSpec.EnvironmentVariables, &ai.DevlabSpec_EnvironmentVariable{ Name: "DEVLAB_SECRET", ValueSource: imageSecret, }, ) } imageRegistryVersion := "<secret_version_ID>" if imageRegistryVersion != "" { imageSpec.RegistryCredentials = &ai.DevlabSpec_RegistryCredentials{ MysteryboxSecretVersion: imageRegistryVersion, } } imageService := sdk.Services().Ai().V1().Devlab() imageOperation, err := imageService.Create( ctx, &ai.CreateDevlabRequest{ Metadata: &common.ResourceMetadata{ ParentId: "<project_ID>", Name: "<devlab_name>", }, Spec: imageSpec, }, ) if err != nil { return fmt.Errorf("create devlab: %w", err) } if _, err = imageOperation.Wait(ctx); err != nil { return fmt.Errorf("wait for devlab creation: %w", err) }Example: Create a Devlab from a container image
nginxSpec := &ai.DevlabSpec{ Image: "docker.io/library/nginx:1.27-alpine", PrimaryRoute: &ai.DevlabSpec_PrimaryRoute{ ContainerPort: 80, }, Ports: []*ai.DevlabSpec_Port{ { ContainerPort: 80, Protocol: ai.DevlabSpec_Port_HTTP, }, }, Platform: "cpu-e2", Preset: "2vcpu-8gb", Disk: &ai.DevlabSpec_DiskSpec{ Type: compute.DiskSpec_NETWORK_SSD, SizeBytes: 268435456000, }, Workspace: &ai.DevlabSpec_Workspace{ ContainerPath: "/workspace", }, SubnetId: "<subnet_ID>", } nginxService := sdk.Services().Ai().V1().Devlab() nginxOperation, err := nginxService.Create( ctx, &ai.CreateDevlabRequest{ Metadata: &common.ResourceMetadata{ ParentId: "<project_ID>", Name: "nginx-devlab", }, Spec: nginxSpec, }, ) if err != nil { return fmt.Errorf("create devlab: %w", err) } if _, err = nginxOperation.Wait(ctx); err != nil { return fmt.Errorf("wait for devlab creation: %w", err) }
-
Devlab settings:
-
Metadata.ParentId: Project ID. -
Metadata.Name: Devlab name. -
Spec.Template.IdorSpec.Image: How to define the container. Specify one of these parameters:Spec.Template.Id: Template ID. Copy itsMetadata.Idfrom the template list. Mutually exclusive withSpec.Image. The template declares the container image, entrypoint command, arguments, working directory, ports, primary web route, and the default workspace path. Don’t setSpec.Image,Spec.ContainerCommand,Spec.Args,Spec.WorkingDir, orSpec.PrimaryRoutewithSpec.Template.Spec.Image: Container image reference in theregistry/path:tagorregistry/path@digestformat. Mutually exclusive withSpec.Template. Required unless you setSpec.Template.
-
Spec.Template.InputFieldValues(optional for some templates; required for JupyterLab): Template inputs as key-value pairs. RequiresSpec.Template. To set several inputs, add an entry for each input. For the JupyterLab template, setSpec.Template.InputFieldValues["jupyter_token"]to a random token of exactly 16 alphanumeric characters that you provide. Save the token securely to sign in later. -
Spec.RegistryCredentials.MysteryboxSecretVersion(optional): SecretStash secret version ID withREGISTRY_USERNAMEandREGISTRY_PASSWORDpayload keys. Use when you pull an image from a private registry. Applies only withSpec.Image. -
Spec.ContainerCommand(optional): Entrypoint command for the container. Applies only withSpec.Image. Declared by the template when you useSpec.Template. -
Spec.Args(optional): Arguments for the entrypoint command. Applies only withSpec.Image. Declared by the template when you useSpec.Template. -
Spec.WorkingDir(optional): Working directory (absolute path). Applies only withSpec.Image. Declared by the template when you useSpec.Template. -
Spec.PrimaryRoute.ContainerPort: Container port for the primary web UI behind the managed HTTPS URL. Required withSpec.Image. Declared by the template when you useSpec.Template. Must match an HTTP port fromSpec.Ports. -
Spec.EnvironmentVariables(optional): Environment variables for the container. Set each variable’sNameandValueSource. To set several variables, add an entry for each variable. WithSpec.Template, these variables extend the template-declared ones. The samples setDEVLAB_ENVto<value>and optionally loadDEVLAB_SECRETfrom a SecretStash secret. For the secret, setSecretIdinai.DevlabSpec_MysteryBoxSecretRefto the secret ID. -
Spec.Ports(optional withSpec.Template; required withSpec.Image): Ports to expose from the container. Set each port’sContainerPortandProtocol. Supported protocols are HTTP, TCP, and UDP; the samples useai.DevlabSpec_Port_HTTP. To expose several ports, add an entry for each port. WithSpec.Template, these ports extend the template-declared ones. Additional ports appear in the Devlab status but aren’t publicly routed unless they are the primary web route. -
Spec.Workspace.ContainerPath: Absolute path of the workspace on the container disk. Data under this path persists across stop and restart. Required withSpec.Image, for example,/workspace. WithSpec.Template, the template declares a default path, which you can override. The path must not overlap mounted volume paths. The workspace size is limited only by the container disk size (Spec.Disk.SizeBytes). -
Spec.Volumes(optional): Bucket or shared filesystem to mount to the Devlab container. SetSourceto the bucket or filesystem ID or name andContainerPathto the destination directory in the container. Volume mount paths must not overlap the workspace path. SetModetoai.DevlabSpec_VolumeMount_READ_ONLYfor read-only access orai.DevlabSpec_VolumeMount_READ_WRITEfor read-write access. To mount several volumes, add an entry for each volume. -
Spec.InjectedFiles(optional): Mount local files into the Devlab container at launch. Set each file’sContainerPathto its absolute destination path andContentto the file’s bytes. Replace<local_path>inos.ReadFilewith the source file’s local path. To inject multiple files, add an entry for each file. Each mounted file is read-only and limited to 64 KiB.
-
-
Underlying VM characteristics:
-
Spec.Platform: VM platform. Choose a platform supported by the template or image. For CPU-only templates, such as Open WebUI, specify a CPU platform. See available platforms in Types of virtual machines and GPUs in Nebius AI Cloud. -
Spec.Preset: Number of GPUs, vCPUs, and RAM allocated to the container. Choose a preset that matches the selected platform. See available presets in Presets for GPU platforms. -
Spec.Disk.SizeBytes: Disk size of the underlying VM in bytes, for example,85899345920for 80 GiB. Set at least 50 GiB for GPU workloads or 20 GiB for CPU-only workloads. If the container image requires a bigger disk size, set at least the minimum required value for the image. Otherwise, the workloads won’t be able to launch. For more information, see how disk performance depends on disk size. -
Spec.ShmSizeBytes(optional): Shared memory size of/dev/shmin bytes, for example,67108864for 64 MiB. WithSpec.Template, you can set this only when the template leaves shared memory unset. -
Spec.SubnetId: Subnet ID for the Devlab. Required if the project has multiple subnets. -
Spec.SshAuthorizedKeys(optional): SSH public keys to access the underlying VM by SSH. To assign a public IP address, also setSpec.PublicIptotrue. Before you add the keys, check the quota on the number of public IP addresses in the web console. -
Spec.PublicIp(optional): Set totrueto assign a public IP address to the underlying VM. Not required to open the Devlab web UI over the managed HTTPS URL.
-
<secret_ID>or<secret_version_ID>with an empty string (""). The samples use a secret ID forDEVLAB_SECRETand a secret version ID for private-registry credentials. -
From a template:
-
If you want to create a Devlab from a template, list the templates and copy the required template’s
metadata.id:template_service = VmAppTemplateServiceClient(sdk) list_templates_request = ListVmAppTemplatesRequest( global_only=True, kind="devlab", ) while True: templates = await template_service.list( list_templates_request, ) print(templates) if not templates.next_page_token: break list_templates_request.page_token = templates.next_page_token -
Create the Devlab. Use either a template or a container image:
-
From a template:
template_spec = DevlabSpec( template=DevlabSpec__Template( id="<template_ID>", input_field_values={ "jupyter_token": Value( string_value="<jupyter_token>", ), }, ), environment_variables=[ DevlabSpec__EnvironmentVariable( name="DEVLAB_ENV", value="<value>", ), ], ports=[ DevlabSpec__Port( container_port=<port>, protocol=DevlabSpec__Port__Protocol.HTTP, ), ], volumes=[ DevlabSpec__VolumeMount( source="<bucket_ID>", container_path="<container_path>", mode=DevlabSpec__VolumeMount__Mode.READ_WRITE, ), ], injected_files=[ DevlabSpec__FileInjection( container_path="<absolute_container_path>", content=Path("<local_path>").read_bytes(), ), ], ssh_authorized_keys=[ "<SSH_public_key>", ], public_ip=True, platform="<platform_ID>", preset="<preset>", disk=DevlabSpec__DiskSpec( type=DiskSpec__DiskType.NETWORK_SSD, size_bytes=<disk_size_in_bytes>, ), workspace=DevlabSpec__Workspace( container_path="<absolute_path>", ), subnet_id="<subnet_ID>", ) template_secret_id = "<secret_ID>" if template_secret_id: template_spec.environment_variables.append( DevlabSpec__EnvironmentVariable( name="DEVLAB_SECRET", mysterybox_secret=DevlabSpec__MysteryBoxSecretRef( secret_id=template_secret_id, ), ), ) template_service = DevlabServiceClient(sdk) template_operation = await template_service.create( CreateDevlabRequest( metadata=ResourceMetadata( parent_id="<project_ID>", name="<devlab_name>", ), spec=template_spec, ), ) await template_operation.wait()Example: Create a Devlab from the JupyterLab template
Replace the sample Jupyter token with your own random token of exactly 16 alphanumeric characters. Save the token securely to sign in to JupyterLab.jupyter_spec = DevlabSpec( template=DevlabSpec__Template( id="vmapptemplate-g00devlab-jupyter", input_field_values={ "jupyter_token": Value( string_value="A1b2C3d4E5f6G7h8", ), }, ), platform="<platform_ID>", preset="<preset>", disk=DevlabSpec__DiskSpec( type=DiskSpec__DiskType.NETWORK_SSD, size_bytes=268435456000, ), workspace=DevlabSpec__Workspace(), subnet_id="<subnet_ID>", ) jupyter_service = DevlabServiceClient(sdk) jupyter_operation = await jupyter_service.create( CreateDevlabRequest( metadata=ResourceMetadata( parent_id="<project_ID>", name="my-jupyter", ), spec=jupyter_spec, ), ) await jupyter_operation.wait() -
From a container image:
image_spec = DevlabSpec( image="<image>", primary_route=DevlabSpec__PrimaryRoute( container_port=<port>, ), ports=[ DevlabSpec__Port( container_port=<port>, protocol=DevlabSpec__Port__Protocol.HTTP, ), ], container_command="<command>", args="<arguments>", working_dir="<absolute_path>", shm_size_bytes=<shared_memory_size_in_bytes>, environment_variables=[ DevlabSpec__EnvironmentVariable( name="DEVLAB_ENV", value="<value>", ), ], volumes=[ DevlabSpec__VolumeMount( source="<bucket_ID>", container_path="<container_path>", mode=DevlabSpec__VolumeMount__Mode.READ_WRITE, ), ], injected_files=[ DevlabSpec__FileInjection( container_path="<absolute_container_path>", content=Path("<local_path>").read_bytes(), ), ], ssh_authorized_keys=[ "<SSH_public_key>", ], public_ip=True, platform="<platform_ID>", preset="<preset>", disk=DevlabSpec__DiskSpec( type=DiskSpec__DiskType.NETWORK_SSD, size_bytes=<disk_size_in_bytes>, ), workspace=DevlabSpec__Workspace( container_path="<absolute_path>", ), subnet_id="<subnet_ID>", ) image_secret_id = "<secret_ID>" if image_secret_id: image_spec.environment_variables.append( DevlabSpec__EnvironmentVariable( name="DEVLAB_SECRET", mysterybox_secret=DevlabSpec__MysteryBoxSecretRef( secret_id=image_secret_id, ), ), ) image_registry_version = "<secret_version_ID>" if image_registry_version: image_spec.registry_credentials = DevlabSpec__RegistryCredentials( mysterybox_secret_version=image_registry_version, ) image_service = DevlabServiceClient(sdk) image_operation = await image_service.create( CreateDevlabRequest( metadata=ResourceMetadata( parent_id="<project_ID>", name="<devlab_name>", ), spec=image_spec, ), ) await image_operation.wait()Example: Create a Devlab from a container image
nginx_spec = DevlabSpec( image="docker.io/library/nginx:1.27-alpine", primary_route=DevlabSpec__PrimaryRoute( container_port=80, ), ports=[ DevlabSpec__Port( container_port=80, protocol=DevlabSpec__Port__Protocol.HTTP, ), ], platform="cpu-e2", preset="2vcpu-8gb", disk=DevlabSpec__DiskSpec( type=DiskSpec__DiskType.NETWORK_SSD, size_bytes=268435456000, ), workspace=DevlabSpec__Workspace( container_path="/workspace", ), subnet_id="<subnet_ID>", ) nginx_service = DevlabServiceClient(sdk) nginx_operation = await nginx_service.create( CreateDevlabRequest( metadata=ResourceMetadata( parent_id="<project_ID>", name="nginx-devlab", ), spec=nginx_spec, ), ) await nginx_operation.wait()
-
Devlab settings:
-
metadata.parent_id: Project ID. -
metadata.name: Devlab name. -
spec.template.idorspec.image: How to define the container. Specify one of these parameters:spec.template.id: Template ID. Copy itsmetadata.idfrom the template list. Mutually exclusive withspec.image. The template declares the container image, entrypoint command, arguments, working directory, ports, primary web route, and the default workspace path. Don’t setspec.image,spec.container_command,spec.args,spec.working_dir, orspec.primary_routewithspec.template.spec.image: Container image reference in theregistry/path:tagorregistry/path@digestformat. Mutually exclusive withspec.template. Required unless you setspec.template.
-
spec.template.input_field_values(optional for some templates; required for JupyterLab): Template inputs as key-value pairs. Requiresspec.template. To set several inputs, add an entry for each input. For the JupyterLab template, setspec.template.input_field_values["jupyter_token"]to a random token of exactly 16 alphanumeric characters that you provide. Save the token securely to sign in later. -
spec.registry_credentials.mysterybox_secret_version(optional): SecretStash secret version ID withREGISTRY_USERNAMEandREGISTRY_PASSWORDpayload keys. Use when you pull an image from a private registry. Applies only withspec.image. -
spec.container_command(optional): Entrypoint command for the container. Applies only withspec.image. Declared by the template when you usespec.template. -
spec.args(optional): Arguments for the entrypoint command. Applies only withspec.image. Declared by the template when you usespec.template. -
spec.working_dir(optional): Working directory (absolute path). Applies only withspec.image. Declared by the template when you usespec.template. -
spec.primary_route.container_port: Container port for the primary web UI behind the managed HTTPS URL. Required withspec.image. Declared by the template when you usespec.template. Must match an HTTP port fromspec.ports. -
spec.environment_variables(optional): Environment variables for the container. Set each variable’snameandvalue. To set several variables, add an entry for each variable. Withspec.template, these variables extend the template-declared ones. The samples setDEVLAB_ENVto<value>and optionally loadDEVLAB_SECRETfrom a SecretStash secret. For the secret, setsecret_idinDevlabSpec__MysteryBoxSecretRefto the secret ID. -
spec.ports(optional withspec.template; required withspec.image): Ports to expose from the container. Set each port’scontainer_portandprotocol. Supported protocols are HTTP, TCP, and UDP; the samples useDevlabSpec__Port__Protocol.HTTP. To expose several ports, add an entry for each port. Withspec.template, these ports extend the template-declared ones. Additional ports appear in the Devlab status but aren’t publicly routed unless they are the primary web route. -
spec.workspace.container_path: Absolute path of the workspace on the container disk. Data under this path persists across stop and restart. Required withspec.image, for example,/workspace. Withspec.template, the template declares a default path, which you can override. The path must not overlap mounted volume paths. The workspace size is limited only by the container disk size (spec.disk.size_bytes). -
spec.volumes(optional): Bucket or shared filesystem to mount to the Devlab container. Setsourceto the bucket or filesystem ID or name andcontainer_pathto the destination directory in the container. Volume mount paths must not overlap the workspace path. SetmodetoDevlabSpec__VolumeMount__Mode.READ_ONLYfor read-only access orDevlabSpec__VolumeMount__Mode.READ_WRITEfor read-write access. To mount several volumes, add an entry for each volume. -
spec.injected_files(optional): Mount local files into the Devlab container at launch. Set each file’scontainer_pathto its absolute destination path andcontentto the file’s bytes. Replace<local_path>inPath(...).read_bytes()with the source file’s local path. To inject multiple files, add an entry for each file. Each mounted file is read-only and limited to 64 KiB.
-
-
Underlying VM characteristics:
-
spec.platform: VM platform. Choose a platform supported by the template or image. For CPU-only templates, such as Open WebUI, specify a CPU platform. See available platforms in Types of virtual machines and GPUs in Nebius AI Cloud. -
spec.preset: Number of GPUs, vCPUs, and RAM allocated to the container. Choose a preset that matches the selected platform. See available presets in Presets for GPU platforms. -
spec.disk.size_bytes: Disk size of the underlying VM in bytes, for example,85899345920for 80 GiB. Set at least 50 GiB for GPU workloads or 20 GiB for CPU-only workloads. If the container image requires a bigger disk size, set at least the minimum required value for the image. Otherwise, the workloads won’t be able to launch. For more information, see how disk performance depends on disk size. -
spec.shm_size_bytes(optional): Shared memory size of/dev/shmin bytes, for example,67108864for 64 MiB. Withspec.template, you can set this only when the template leaves shared memory unset. -
spec.subnet_id: Subnet ID for the Devlab. Required if the project has multiple subnets. -
spec.ssh_authorized_keys(optional): SSH public keys to access the underlying VM by SSH. To assign a public IP address, also setspec.public_iptoTrue. Before you add the keys, check the quota on the number of public IP addresses in the web console. -
spec.public_ip(optional): Set toTrueto assign a public IP address to the underlying VM. Not required to open the Devlab web UI over the managed HTTPS URL.
-
<secret_ID>or<secret_version_ID>with an empty string (""). The samples use a secret ID forDEVLAB_SECRETand a secret version ID for private-registry credentials. -
From a template:
-
If you want to create a Devlab from a template, list the templates and copy the required template’s
metadata.id:const listTemplateService = new VmAppTemplateService(sdk); const listTemplatesRequest = ListVmAppTemplatesRequest.create({ globalOnly: true, kind: "devlab", }); while (true) { const templates = await listTemplateService.list( listTemplatesRequest, ); console.log(templates); if (!templates.nextPageToken) { break; } listTemplatesRequest.pageToken = templates.nextPageToken; } -
Create the Devlab. Use either a template or a container image:
-
From a template:
const templateSpec = DevlabSpec.create({ template: { id: "<template_ID>", inputFieldValues: { jupyter_token: "<jupyter_token>", }, }, environmentVariables: [ { name: "DEVLAB_ENV", valueSource: { $case: "value", value: "<value>", }, }, ], ports: [ { containerPort: <port>, protocol: DevlabSpec_Port_Protocol.HTTP, }, ], volumes: [ { source: "<bucket_ID>", containerPath: "<container_path>", mode: DevlabSpec_VolumeMount_Mode.READ_WRITE, }, ], injectedFiles: [ { containerPath: "<absolute_container_path>", content: await readFile("<local_path>"), }, ], sshAuthorizedKeys: [ "<SSH_public_key>", ], publicIp: true, platform: "<platform_ID>", preset: "<preset>", disk: { type: DiskSpec_DiskType.NETWORK_SSD, sizeBytes: <disk_size_in_bytes>, }, workspace: { containerPath: "<absolute_path>", }, subnetId: "<subnet_ID>", }); const templateSecretId = "<secret_ID>"; if (templateSecretId) { templateSpec.environmentVariables.push( DevlabSpec_EnvironmentVariable.create({ name: "DEVLAB_SECRET", valueSource: { $case: "mysteryboxSecret", mysteryboxSecret: { secretId: templateSecretId }, }, }), ); } const templateService = new DevlabService(sdk); const templateOperation = await templateService.create( CreateDevlabRequest.create({ metadata: { parentId: "<project_ID>", name: "<devlab_name>", }, spec: templateSpec, }), ).result; await templateOperation.wait();Example: Create a Devlab from the JupyterLab template
Replace the sample Jupyter token with your own random token of exactly 16 alphanumeric characters. Save the token securely to sign in to JupyterLab.const jupyterSpec = DevlabSpec.create({ template: { id: "vmapptemplate-g00devlab-jupyter", inputFieldValues: { jupyter_token: "A1b2C3d4E5f6G7h8", }, }, platform: "<platform_ID>", preset: "<preset>", disk: { type: DiskSpec_DiskType.NETWORK_SSD, sizeBytes: 268435456000, }, workspace: {}, subnetId: "<subnet_ID>", }); const jupyterService = new DevlabService(sdk); const jupyterOperation = await jupyterService.create( CreateDevlabRequest.create({ metadata: { parentId: "<project_ID>", name: "my-jupyter", }, spec: jupyterSpec, }), ).result; await jupyterOperation.wait(); -
From a container image:
const imageSpec = DevlabSpec.create({ image: "<image>", primaryRoute: { containerPort: <port>, }, ports: [ { containerPort: <port>, protocol: DevlabSpec_Port_Protocol.HTTP, }, ], containerCommand: "<command>", args: "<arguments>", workingDir: "<absolute_path>", shmSizeBytes: <shared_memory_size_in_bytes>, environmentVariables: [ { name: "DEVLAB_ENV", valueSource: { $case: "value", value: "<value>", }, }, ], volumes: [ { source: "<bucket_ID>", containerPath: "<container_path>", mode: DevlabSpec_VolumeMount_Mode.READ_WRITE, }, ], injectedFiles: [ { containerPath: "<absolute_container_path>", content: await readFile("<local_path>"), }, ], sshAuthorizedKeys: [ "<SSH_public_key>", ], publicIp: true, platform: "<platform_ID>", preset: "<preset>", disk: { type: DiskSpec_DiskType.NETWORK_SSD, sizeBytes: <disk_size_in_bytes>, }, workspace: { containerPath: "<absolute_path>", }, subnetId: "<subnet_ID>", }); const imageSecretId = "<secret_ID>"; if (imageSecretId) { imageSpec.environmentVariables.push( DevlabSpec_EnvironmentVariable.create({ name: "DEVLAB_SECRET", valueSource: { $case: "mysteryboxSecret", mysteryboxSecret: { secretId: imageSecretId }, }, }), ); } const imageRegistryVersion = "<secret_version_ID>"; if (imageRegistryVersion) { imageSpec.registryCredentials = DevlabSpec_RegistryCredentials.create({ mysteryboxSecretVersion: imageRegistryVersion, }); } const imageService = new DevlabService(sdk); const imageOperation = await imageService.create( CreateDevlabRequest.create({ metadata: { parentId: "<project_ID>", name: "<devlab_name>", }, spec: imageSpec, }), ).result; await imageOperation.wait();Example: Create a Devlab from a container image
const nginxSpec = DevlabSpec.create({ image: "docker.io/library/nginx:1.27-alpine", primaryRoute: { containerPort: 80, }, ports: [ { containerPort: 80, protocol: DevlabSpec_Port_Protocol.HTTP, }, ], platform: "cpu-e2", preset: "2vcpu-8gb", disk: { type: DiskSpec_DiskType.NETWORK_SSD, sizeBytes: 268435456000, }, workspace: { containerPath: "/workspace", }, subnetId: "<subnet_ID>", }); const nginxService = new DevlabService(sdk); const nginxOperation = await nginxService.create( CreateDevlabRequest.create({ metadata: { parentId: "<project_ID>", name: "nginx-devlab", }, spec: nginxSpec, }), ).result; await nginxOperation.wait();
-
Devlab settings:
-
metadata.parentId: Project ID. -
metadata.name: Devlab name. -
spec.template.idorspec.image: How to define the container. Specify one of these parameters:spec.template.id: Template ID. Copy itsmetadata.idfrom the template list. Mutually exclusive withspec.image. The template declares the container image, entrypoint command, arguments, working directory, ports, primary web route, and the default workspace path. Don’t setspec.image,spec.containerCommand,spec.args,spec.workingDir, orspec.primaryRoutewithspec.template.spec.image: Container image reference in theregistry/path:tagorregistry/path@digestformat. Mutually exclusive withspec.template. Required unless you setspec.template.
-
spec.template.inputFieldValues(optional for some templates; required for JupyterLab): Template inputs as key-value pairs. Requiresspec.template. To set several inputs, add an entry for each input. For the JupyterLab template, setspec.template.inputFieldValues.jupyter_tokento a random token of exactly 16 alphanumeric characters that you provide. Save the token securely to sign in later. -
spec.registryCredentials.mysteryboxSecretVersion(optional): SecretStash secret version ID withREGISTRY_USERNAMEandREGISTRY_PASSWORDpayload keys. Use when you pull an image from a private registry. Applies only withspec.image. -
spec.containerCommand(optional): Entrypoint command for the container. Applies only withspec.image. Declared by the template when you usespec.template. -
spec.args(optional): Arguments for the entrypoint command. Applies only withspec.image. Declared by the template when you usespec.template. -
spec.workingDir(optional): Working directory (absolute path). Applies only withspec.image. Declared by the template when you usespec.template. -
spec.primaryRoute.containerPort: Container port for the primary web UI behind the managed HTTPS URL. Required withspec.image. Declared by the template when you usespec.template. Must match an HTTP port fromspec.ports. -
spec.environmentVariables(optional): Environment variables for the container. Set each variable’snameandvalueSource. To set several variables, add an entry for each variable. Withspec.template, these variables extend the template-declared ones. The samples setDEVLAB_ENVto<value>and optionally loadDEVLAB_SECRETfrom a SecretStash secret. For the secret, setvalueSource.mysteryboxSecret.secretIdto the secret ID andvalueSource.$caseto"mysteryboxSecret". -
spec.ports(optional withspec.template; required withspec.image): Ports to expose from the container. Set each port’scontainerPortandprotocol. Supported protocols are HTTP, TCP, and UDP; the samples useDevlabSpec_Port_Protocol.HTTP. To expose several ports, add an entry for each port. Withspec.template, these ports extend the template-declared ones. Additional ports appear in the Devlab status but aren’t publicly routed unless they are the primary web route. -
spec.workspace.containerPath: Absolute path of the workspace on the container disk. Data under this path persists across stop and restart. Required withspec.image, for example,/workspace. Withspec.template, the template declares a default path, which you can override. The path must not overlap mounted volume paths. The workspace size is limited only by the container disk size (spec.disk.sizeBytes). -
spec.volumes(optional): Bucket or shared filesystem to mount to the Devlab container. Setsourceto the bucket or filesystem ID or name andcontainerPathto the destination directory in the container. Volume mount paths must not overlap the workspace path. SetmodetoDevlabSpec_VolumeMount_Mode.READ_ONLYfor read-only access orDevlabSpec_VolumeMount_Mode.READ_WRITEfor read-write access. To mount several volumes, add an entry for each volume. -
spec.injectedFiles(optional): Mount local files into the Devlab container at launch. Set each file’scontainerPathto its absolute destination path andcontentto the file’s bytes. Replace<local_path>inreadFilefromnode:fs/promiseswith the source file’s local path. To inject multiple files, add an entry for each file. Each mounted file is read-only and limited to 64 KiB.
-
-
Underlying VM characteristics:
-
spec.platform: VM platform. Choose a platform supported by the template or image. For CPU-only templates, such as Open WebUI, specify a CPU platform. See available platforms in Types of virtual machines and GPUs in Nebius AI Cloud. -
spec.preset: Number of GPUs, vCPUs, and RAM allocated to the container. Choose a preset that matches the selected platform. See available presets in Presets for GPU platforms. -
spec.disk.sizeBytes: Disk size of the underlying VM in bytes, for example,85899345920for 80 GiB. Set at least 50 GiB for GPU workloads or 20 GiB for CPU-only workloads. If the container image requires a bigger disk size, set at least the minimum required value for the image. Otherwise, the workloads won’t be able to launch. For more information, see how disk performance depends on disk size. -
spec.shmSizeBytes(optional): Shared memory size of/dev/shmin bytes, for example,67108864for 64 MiB. Withspec.template, you can set this only when the template leaves shared memory unset. -
spec.subnetId: Subnet ID for the Devlab. Required if the project has multiple subnets. -
spec.sshAuthorizedKeys(optional): SSH public keys to access the underlying VM by SSH. To assign a public IP address, also setspec.publicIptotrue. Before you add the keys, check the quota on the number of public IP addresses in the web console. -
spec.publicIp(optional): Set totrueto assign a public IP address to the underlying VM. Not required to open the Devlab web UI over the managed HTTPS URL.
-
<secret_ID>or<secret_version_ID>with an empty string (""). The samples use a secret ID forDEVLAB_SECRETand a secret version ID for private-registry credentials. -
From a template:
How to open a Devlab
When a Devlab is running, you can open its web UI over a managed HTTPS URL. A public IP address isn’t required. If you configured an SSH key and network access that allows SSH, you can also connect to the VM by SSH.- Web console
- CLI
- Go SDK
- Python SDK
- JavaScript SDK
- In the sidebar, go to
Serverless AI → Devlabs.
- Open the page of the required Devlab.
- Wait until the Devlab is running. Then, in the Network section, copy the public Devlab address from the Public Devlabs field.
- In a browser, open the URL. For the JupyterLab template, enter the Jupyter token in the JupyterLab password field. If you created the Devlab in the console, use the token that the console generated.
-
List Devlabs and copy the ID of the Devlab to open:
You can also copy the Devlab ID from the web console. Go to
nebius ai devlab listServerless AI → Devlabs. The ID is shown under the Devlab name.
-
Get the Devlab details and copy the HTTPS URL from the output:
nebius ai devlab get <devlab_ID> -
In a browser, open the HTTPS URL. For the JupyterLab template, enter the
jupyter_tokenvalue that you set at create time in the JupyterLab password field.
-
List Devlabs:
In
listDevlabService := sdk.Services().Ai().V1().Devlab() listDevlabsRequest := &ai.ListDevlabsRequest{ ParentId: "<project_ID>", } for { devlabs, err := listDevlabService.List( ctx, listDevlabsRequest, ) if err != nil { return fmt.Errorf("list devlabs: %w", err) } fmt.Println(devlabs) if devlabs.GetNextPageToken() == "" { break } listDevlabsRequest.PageToken = devlabs.GetNextPageToken() }ai.ListDevlabsRequest, setParentIdto the project ID. In the response, copy theMetadata.Idof the required Devlab. -
Get the Devlab details:
In
getDevlabService := sdk.Services().Ai().V1().Devlab() devlab, err := getDevlabService.Get( ctx, &ai.GetDevlabRequest{Id: "<devlab_ID>"}, ) if err != nil { return fmt.Errorf("get devlab: %w", err) } fmt.Println(devlab)ai.GetDevlabRequest, setIdto the Devlab ID. Copy the HTTPS URL fromStatus.PublicEndpointsin the response. - In a browser, open the HTTPS URL. For JupyterLab, enter the token that you supplied when creating the Devlab in the JupyterLab password field.
-
List Devlabs:
In
list_devlab_service = DevlabServiceClient(sdk) list_devlabs_request = ListDevlabsRequest( parent_id="<project_ID>", ) while True: devlabs = await list_devlab_service.list( list_devlabs_request, ) print(devlabs) if not devlabs.next_page_token: break list_devlabs_request.page_token = devlabs.next_page_tokenListDevlabsRequest, setparent_idto the project ID. In the response, copy themetadata.idof the required Devlab. -
Get the Devlab details:
In
get_devlab_service = DevlabServiceClient(sdk) devlab = await get_devlab_service.get( GetDevlabRequest(id="<devlab_ID>"), ) print(devlab)GetDevlabRequest, setidto the Devlab ID. Copy the HTTPS URL fromstatus.public_endpointsin the response. - In a browser, open the HTTPS URL. For JupyterLab, enter the token that you supplied when creating the Devlab in the JupyterLab password field.
-
List Devlabs:
In
const listDevlabService = new DevlabService(sdk); const listDevlabsRequest = ListDevlabsRequest.create({ parentId: "<project_ID>", }); while (true) { const devlabs = await listDevlabService.list( listDevlabsRequest, ); console.log(devlabs); if (!devlabs.nextPageToken) { break; } listDevlabsRequest.pageToken = devlabs.nextPageToken; }ListDevlabsRequest, setparentIdto the project ID. In the response, copy themetadata.idof the required Devlab. -
Get the Devlab details:
In
const getDevlabService = new DevlabService(sdk); const devlab = await getDevlabService.get( GetDevlabRequest.create({ id: "<devlab_ID>" }), ); console.log(devlab);GetDevlabRequest, setidto the Devlab ID. Copy the HTTPS URL fromstatus.publicEndpointsin the response. - In a browser, open the HTTPS URL. For JupyterLab, enter the token that you supplied when creating the Devlab in the JupyterLab password field.
How to check Devlab logs
To view logs from a running or stopped Devlab:- Web console
- CLI
- In the sidebar, go to
Serverless AI → Devlabs.
- Next to the Devlab, click View logs. Alternatively, select the Devlab and switch to the Logs tab.
Run the following command:
nebius ai devlab logs <devlab_ID> --follow
How to delete a Devlab
When you delete a Devlab, Serverless AI automatically deletes its VM and container disk. If you no longer need the Devlab, delete it:- Web console
- CLI
- Go SDK
- Python SDK
- JavaScript SDK
- In the sidebar, go to
Serverless AI → Devlabs.
- Find the Devlab and then click
→ Delete.
- In the window that opens, confirm the deletion.
-
List Devlabs and copy the ID of the Devlab you want to delete:
nebius ai devlab list -
Delete the Devlab:
nebius ai devlab delete <devlab_ID>
-
List Devlabs:
In
listDevlabService := sdk.Services().Ai().V1().Devlab() listDevlabsRequest := &ai.ListDevlabsRequest{ ParentId: "<project_ID>", } for { devlabs, err := listDevlabService.List( ctx, listDevlabsRequest, ) if err != nil { return fmt.Errorf("list devlabs: %w", err) } fmt.Println(devlabs) if devlabs.GetNextPageToken() == "" { break } listDevlabsRequest.PageToken = devlabs.GetNextPageToken() }ai.ListDevlabsRequest, setParentIdto the project ID. In the response, copy theMetadata.Idof the required Devlab. -
Delete the Devlab:
In
deleteDevlabService := sdk.Services().Ai().V1().Devlab() deleteDevlabOperation, err := deleteDevlabService.Delete( ctx, &ai.DeleteDevlabRequest{Id: "<devlab_ID>"}, ) if err != nil { return fmt.Errorf("delete devlab: %w", err) } if _, err = deleteDevlabOperation.Wait(ctx); err != nil { return fmt.Errorf("wait for devlab delete: %w", err) }ai.DeleteDevlabRequest, setIdto the Devlab ID. The sample waits for deletion to complete.
-
List Devlabs:
In
list_devlab_service = DevlabServiceClient(sdk) list_devlabs_request = ListDevlabsRequest( parent_id="<project_ID>", ) while True: devlabs = await list_devlab_service.list( list_devlabs_request, ) print(devlabs) if not devlabs.next_page_token: break list_devlabs_request.page_token = devlabs.next_page_tokenListDevlabsRequest, setparent_idto the project ID. In the response, copy themetadata.idof the required Devlab. -
Delete the Devlab:
In
delete_devlab_service = DevlabServiceClient(sdk) delete_devlab_operation = await delete_devlab_service.delete( DeleteDevlabRequest(id="<devlab_ID>"), ) await delete_devlab_operation.wait()DeleteDevlabRequest, setidto the Devlab ID. The sample waits for deletion to complete.
-
List Devlabs:
In
const listDevlabService = new DevlabService(sdk); const listDevlabsRequest = ListDevlabsRequest.create({ parentId: "<project_ID>", }); while (true) { const devlabs = await listDevlabService.list( listDevlabsRequest, ); console.log(devlabs); if (!devlabs.nextPageToken) { break; } listDevlabsRequest.pageToken = devlabs.nextPageToken; }ListDevlabsRequest, setparentIdto the project ID. In the response, copy themetadata.idof the required Devlab. -
Delete the Devlab:
In
const deleteDevlabService = new DevlabService(sdk); const deleteDevlabOperation = await deleteDevlabService.delete( DeleteDevlabRequest.create({ id: "<devlab_ID>" }), ).result; await deleteDevlabOperation.wait();DeleteDevlabRequest, setidto the Devlab ID. The sample waits for deletion to complete.
See also
“Jupyter” and the Jupyter logos are trademarks or registered trademarks of LF Charities, used by Nebius B.V. with permission.