Spring BootのProfileを使って環境によって違う設定を安全に切り替える方法


Profileとは何か

Spring BootのProfileは、「今どの環境で動いているか(開発・検証・本番など)」を表すスイッチです。
このスイッチに応じて、Beanの有効/無効や設定値(DB接続先、ログレベル、外部APIのURLなど)を切り替えられます。

たとえば次のような切り替えを安全に行えます。

  • 開発ではH2、本番ではPostgreSQL
  • 開発では詳細ログ、本番ではINFO中心
  • 開発ではモックの外部API、本番では実API

「設定を手で書き換えてデプロイ」みたいな事故を減らせるのが、Profileの大きな価値です。

Profileで何が切り替わるのか

Profileで主に切り替える対象は次の2つです。

  • 設定ファイル(application.yml / properties)の値
  • SpringのBean定義(@Bean / @Component など)の有効化

設定ファイルをProfileごとに分ける基本

一番よく使うのが、application-<profile>.yml(または.properties)での分割です。

たとえば、以下のように分割することができます。

  • application.yml(共通)
  • application-dev.yml(開発用)
  • application-prod.yml(本番用)
  • application-test.yml(テスト用)

application.yml(共通)

spring:
  application:
    name: demo

logging:
  level:
    root: INFO

application-dev.yml(開発)

spring:
  datasource:
    url: jdbc:h2:mem:testdb
  jpa:
    hibernate:
      ddl-auto: create-drop

logging:
  level:
    root: DEBUG

application-prod.yml(本番)

spring:
  datasource:
    url: jdbc:postgresql://db.prod.example.com:5432/app
  jpa:
    hibernate:
      ddl-auto: validate

logging:
  level:
    root: INFO

application-test.yml(テスト)

spring:
  datasource:
    url: jdbc:h2:mem:testdb
  jpa:
    hibernate:
      ddl-auto: create-drop

logging:
  level:
    root: WARN

ポイントは「共通はapplication.ymlに置き、環境差分だけをprofile側に書く」ことです。
差分が見やすくなり、設定の重複も減ります。

Profileを有効化する方法

Profileの有効化(どれを使うか)はいくつか方法があります。よく使う順に紹介します。

起動引数で指定する

ローカル実行や一時的な切り替えで便利です。

java -jar app.jar --spring.profiles.active=dev

環境変数で指定する

DockerやKubernetesなど、コンテナ運用でよく使います。

export SPRING_PROFILES_ACTIVE=prod

application.ymlで指定する(おすすめしない場面もある)

spring:
  profiles:
    active: dev

これは「常にdevで動く」状態になりやすいので注意です。
CI/CDや本番デプロイが絡むなら、環境変数やデプロイ設定側で制御する方が安全です。

Gradleでテスト実行時だけ常にtest Profileを有効にする

./gradlew test でテストを走らせるときだけ、毎回 test Profileにしたい」なら、Gradleのtestタスクにシステムプロパティとして渡すのが簡単です。

Groovy DSL(build.gradle)

tasks.named('test') {
    useJUnitPlatform()
    systemProperty 'spring.profiles.active', 'test'
}

これで、Gradle経由でテストを実行する限り test Profileが常に有効になります。

環境変数で渡したい場合は次のようにも書けます。

tasks.named('test') {
    useJUnitPlatform()
    environment 'SPRING_PROFILES_ACTIVE', 'test'
}

Kotlin DSL(build.gradle.kts)

tasks.test {
    useJUnitPlatform()
    systemProperty("spring.profiles.active", "test")
}

注意点

  • この設定は「Gradleのtestタスク」にだけ効きます。bootRunなどには影響しません。
  • IDEの「JUnitを直接実行(Gradleを使わない実行設定)」だと、この設定が反映されないことがあります。その場合はIDE側を「Gradleでテスト実行」に切り替えるか、テストクラスに@ActiveProfiles("test")を付ける方法も検討してください。

ProfileでBeanを切り替える

設定値だけでなく、BeanそのものもProfileで出し分けできます。

@Profileでクラス単位に切り替え

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

@Profile("dev")
@Component
public class DevOnlyInitializer {
}

このBeanはdev Profileのときだけ登録されます。

@Configuration + @Beanにも使える

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
public class ClientConfig {

    @Profile("dev")
    @Bean
    public ApiClient mockClient() {
        return new ApiClient("http://localhost:8081");
    }

    @Profile("prod")
    @Bean
    public ApiClient realClient() {
        return new ApiClient("https://api.example.com");
    }
}

これで、外部APIクライアントを環境で差し替える、といった構成が作れます。

1つだけじゃないProfileの指定

Profileは複数同時に有効化できます。

--spring.profiles.active=dev,feature-x

この場合、devfeature-x の両方が有効になります。
「環境」と「機能フラグ」を分ける設計にすると、切り替えがスムーズです。

groupでまとめて有効化する

Profileが増えてくると「devを選ぶと、dev用+ローカル用も一緒にONにしたい」みたいな要望が出ます。
そのときはProfile Groupが便利です。

spring:
  profiles:
    group:
      dev:
        - dev
        - local

これで spring.profiles.active=dev とすると devlocal がまとめて有効になります。

よくある落とし穴と対策

本番にdev設定で起動してしまう

原因はだいたい次のどれかです。

  • application.ymlspring.profiles.active=devを書いている
  • デプロイ環境で環境変数が設定されていない
  • 起動スクリプトが古い

対策としては、「本番は必ずデプロイ設定でSPRING_PROFILES_ACTIVE=prodを明示する」を強くおすすめします。

設定の優先順位がわからなくなる

同じキーが複数箇所にあると混乱します。基本イメージはこうです。

  • 「より外側(環境変数や起動引数)」が強い
  • 「より具体(profile側)」が強いことが多い

困ったら、起動ログにどのProfileが有効かが出るので、まずそこを確認すると解決が早いです。

application-xxx.ymlが読み込まれていない

Profile名のタイプミスが多いです。

  • application-prod.ymlを用意したのに --spring.profiles.active=production で起動している
    → ファイル名とProfile名は一致させる必要があります

開発と運用でのおすすめ構成

迷ったらこの形が扱いやすいです。

  • application.yml:共通設定
  • application-dev.yml:開発環境の差分
  • application-prod.yml:本番環境の差分
  • application-test.yml:テスト環境の差分
  • 起動時に SPRING_PROFILES_ACTIVE を必ず明示(特に本番)

「本番にだけ置くべき値(パスワード、APIキーなど)」は、設定ファイルに直書きせず、環境変数やシークレット管理(Kubernetes Secretなど)で渡すのが安全です。

まとめ

Spring BootのProfileを使うと、環境ごとの設定やBeanを安全に切り替えられます。

  • application-<profile>.ymlで設定値を分ける
  • --spring.profiles.activeSPRING_PROFILES_ACTIVE で有効化する
  • @ProfileでBeanを環境ごとに差し替えられる
  • Gradleのtestタスクで spring.profiles.active=test を渡すと、テスト実行時だけProfileを固定できる
  • 本番は「必ず明示的にprodを指定」して事故を防ぐ

Profileを活用して、安全に環境を分離してみてください!