awesome-hacks
Docs

NestJS Azure Blob Storageにファイルをアップロードする

@azure/storage-blob を使いBlobServiceClientでコンテナへ接続し、NestJSからファイルをアップロードする基本パターン

最終更新:2026/06/05

NestJS基礎まで終えている前提。
この記事では、Azure Blob Storageに対してファイルをアップロードする最小パターンを実装する。BlobServiceClient でストレージアカウントに接続し、getContainerClientgetBlockBlobClient の流れでBlobに書き込む。

この記事でやること

  • @azure/storage-blob を導入する
  • AzureBlobServiceBlobServiceClient / getContainerClient / getBlockBlobClient を使ったアップロードロジックを実装する
  • POST /files/upload でmultipartファイルを受け取り、Blobに保存してURLを返す
  • curl でファイルのアップロードを確認する

触るファイル一覧

api-sample/
└─ src/
   ├─ app.module.ts                         # AzureBlobModule / FilesModuleを追加
   ├─ azure-blob/
   │  ├─ azure-blob.module.ts               # 新規作成
   │  └─ azure-blob.service.ts              # 新規作成(アップロードロジック)
   └─ files/
      ├─ files.module.ts                    # 新規作成
      └─ files.controller.ts               # 新規作成(POST /files/upload)

0. パッケージを追加する

pnpmの場合。

pnpm add @azure/storage-blob
pnpm add -D @types/multer

npmの場合。

npm install @azure/storage-blob
npm install --save-dev @types/multer

@azure/storage-blob はAzure公式のNode.js SDK。@types/multer はNestJSのファイルアップロードで使うmulterの型定義。

1. 環境変数を追加する

.env に接続文字列とコンテナ名を追加する。接続文字列はAzureポータルの「ストレージアカウント → アクセスキー」から取得できる。

AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=https;AccountName=<account>;AccountKey=<key>;EndpointSuffix=core.windows.net
AZURE_STORAGE_CONTAINER_NAME=uploads

2. AzureBlobService を作る

2-1. azure-blob.service.ts を作る

新規作成するファイルは api-sample/src/azure-blob/azure-blob.service.ts

import { Injectable } from "@nestjs/common";
import { BlobServiceClient, BlockBlobClient } from "@azure/storage-blob";

@Injectable()
export class AzureBlobService {
  private readonly blobServiceClient: BlobServiceClient;
  private readonly containerName: string;

  constructor() {
    const connectionString = process.env.AZURE_STORAGE_CONNECTION_STRING;
    if (!connectionString) {
      throw new Error("AZURE_STORAGE_CONNECTION_STRING is not set");
    }
    this.containerName =
      process.env.AZURE_STORAGE_CONTAINER_NAME ?? "uploads";
    this.blobServiceClient =
      BlobServiceClient.fromConnectionString(connectionString);
  }

  async upload(
    fileName: string,
    buffer: Buffer,
    mimeType: string,
  ): Promise<string> {
    const containerClient = this.blobServiceClient.getContainerClient(
      this.containerName,
    );
    // コンテナが存在しない場合は作成する
    await containerClient.createIfNotExists({ access: "blob" });

    const blobName = `${crypto.randomUUID()}-${fileName}`;
    const blockBlobClient: BlockBlobClient =
      containerClient.getBlockBlobClient(blobName);

    await blockBlobClient.uploadData(buffer, {
      blobHTTPHeaders: { blobContentType: mimeType },
    });

    return blockBlobClient.url;
  }
}
  • BlobServiceClient.fromConnectionString で接続文字列からクライアントを作る
  • getContainerClient でコンテナへの操作クライアントを取得する
  • createIfNotExists でコンテナが無ければ自動作成する(2回目以降は何もしない)
  • getBlockBlobClient にBlobの名前を渡し、uploadData でBufferを書き込む
  • blockBlobClient.url がアップロード後のアクセスURLになる

2-2. azure-blob.module.ts を作る

新規作成するファイルは api-sample/src/azure-blob/azure-blob.module.ts

import { Module } from "@nestjs/common";
import { AzureBlobService } from "./azure-blob.service";

@Module({
  providers: [AzureBlobService],
  exports: [AzureBlobService],
})
export class AzureBlobModule {}

exports に追加することで、AzureBlobModule をimportした他のModuleから AzureBlobService を注入できる。

3. FilesModule / FilesController を作る

3-1. files.controller.ts を作る

新規作成するファイルは api-sample/src/files/files.controller.ts

import {
  Controller,
  Post,
  UploadedFile,
  UseInterceptors,
  BadRequestException,
} from "@nestjs/common";
import { FileInterceptor } from "@nestjs/platform-express";
import { AzureBlobService } from "../azure-blob/azure-blob.service";

@Controller("files")
export class FilesController {
  constructor(private readonly azureBlobService: AzureBlobService) {}

  @Post("upload")
  @UseInterceptors(FileInterceptor("file"))
  async upload(
    @UploadedFile() file: Express.Multer.File,
  ): Promise<{ url: string }> {
    if (!file) {
      throw new BadRequestException("ファイルが指定されていません");
    }

    const url = await this.azureBlobService.upload(
      file.originalname,
      file.buffer,
      file.mimetype,
    );
    return { url };
  }
}

FileInterceptor("file") の引数はフォームフィールド名。@UploadedFile() でmulterが解析したファイルを受け取る。file.buffer にファイルの内容が入っており、これをそのまま AzureBlobService.upload に渡す。

3-2. files.module.ts を作る

新規作成するファイルは api-sample/src/files/files.module.ts

import { Module } from "@nestjs/common";
import { FilesController } from "./files.controller";
import { AzureBlobModule } from "../azure-blob/azure-blob.module";

@Module({
  imports: [AzureBlobModule],
  controllers: [FilesController],
})
export class FilesModule {}

4. AppModule に追加する

編集するファイルは api-sample/src/app.module.ts

import { Module } from "@nestjs/common";
import { UsersModule } from "./users/users.module";
import { AuthModule } from "./auth/auth.module";
import { AzureBlobModule } from "./azure-blob/azure-blob.module";
import { FilesModule } from "./files/files.module";

@Module({
  imports: [
    UsersModule,
    AuthModule,
    AzureBlobModule,
    FilesModule,
  ],
})
export class AppModule {}

5. 動作確認

アプリを起動する。

pnpm start:dev

別ターミナルでファイルをアップロードする。

curl -X POST http://localhost:3000/files/upload \
  -F "file=@/path/to/image.png"

成功すると次のようなレスポンスが返る。

{
  "url": "https://<account>.blob.core.windows.net/uploads/abc123-image.png"
}

返ってきたURLにブラウザからアクセスしてファイルが表示されれば完了。

よくあるエラー

AZURE_STORAGE_CONNECTION_STRING is not set

.env に接続文字列が設定されていないか、アプリ起動時に環境変数が読み込まれていない。@nestjs/config を使っている場合は AppModuleConfigModule.forRoot() が追加されているか確認する。

ContainerNotFound

createIfNotExists を呼んでいない場合、コンテナが存在しないとエラーになる。AzureBlobService.upload 内で createIfNotExistsgetBlockBlobClient より前に呼ばれているか確認する。

AuthenticationFailed

接続文字列のアカウントキーが間違っているか期限切れ。Azureポータルで再発行したキーで .env を更新する。

file.bufferundefined

multerが diskStorage で動いている場合に起きる。FileInterceptor にオプションを明示して memoryStorage を指定する。

import { memoryStorage } from "multer";

@UseInterceptors(
  FileInterceptor("file", { storage: memoryStorage() }),
)

実装タスク(チェックリスト)

  • @azure/storage-blob@types/multer をインストール
  • .envAZURE_STORAGE_CONNECTION_STRINGAZURE_STORAGE_CONTAINER_NAME を追加
  • src/azure-blob/azure-blob.service.ts を作成(BlobServiceClient.fromConnectionString / getContainerClient / createIfNotExists / getBlockBlobClient / uploadData
  • src/azure-blob/azure-blob.module.ts を作成(AzureBlobServiceprovidersexports に追加)
  • src/files/files.controller.ts を作成(@Post("upload") / FileInterceptor / @UploadedFile
  • src/files/files.module.ts を作成(AzureBlobModule をimport)
  • AppModuleAzureBlobModuleFilesModule を追加
  • pnpm start:devcurl -X POST ... -F "file=@..." でアップロードを確認

参考