Today
-
Yesterday
-
Total
-

ABOUT ME

-

방문자

  • [.NET 11] .NET 11 GA 정식 릴리즈 핵심 변경점과 실무 마이그레이션 가이드
    Microsoft .NET/ASP.Net & ASP.Net Core 2026. 11. 11. 11:47

    .NET 11이 2026년 11월 10일 GA로 공개됐습니다. 이 글은 실무 프로젝트를 .NET 11로 올릴 때 먼저 확인해야 하는 변경점과 마이그레이션 절차를 순서대로 정리한 것입니다. .NET 11은 STS(Standard Term Support) 릴리즈로 지원 기간이 2년이며, LTS가 필요한 조직은 .NET 10을 계속 쓰는 선택지가 유지됩니다.

     

    절차

     

    1. 릴리즈 기준값 확인
    2. 최소 하드웨어 요구사항 변경 확인 (실무에서 가장 먼저 걸리는 지점)
    3. C# 15 언어 변경점 적용
    4. SDK·툴링 변경점 반영
    5. ASP.NET Core·EF Core 11 변경점 반영
    6. 마이그레이션 실행 순서
    7. 배포 후 롤백 기준

     

    1. 릴리즈 기준값

     

    공식 발표와 다운로드 페이지, GitHub 릴리즈 태그에서 확인한 값입니다.

     

    1. 버전: .NET 11.0.0, SDK 11.0.100 (2026-11-10 공개)
    2. 지원 정책: STS, 2년 지원. .NET 10은 LTS로 계속 지원됩니다.
    3. 기본 언어 버전: C# 15.0 (net11.0 대상 프로젝트 기준). F# 11.0, Visual Basic 17.13이 함께 포함됩니다.
    4. 개발 도구: Visual Studio 2026 (18.12)에 포함.
    5. 같은 날 .NET 10.0.15, .NET 9.0.23, .NET 8.0.34 서비스 업데이트도 함께 배포됐습니다.

     

    버전은 SDK에서 바로 확인합니다.

     

    dotnet --list-sdks
    dotnet --list-runtimes

     

    2. 최소 하드웨어 요구사항 변경

     

    .NET 11에서 가장 먼저 장애로 나타나는 변경입니다. JIT/AOT 기준 ISA 베이스라인이 x86-64-v1에서 x86-64-v2로 올라갔습니다. v2는 CMOV, CX8, SSE, SSE2에 더해 CX16, POPCNT, SSE3, SSSE3, SSE4.1, SSE4.2를 보장합니다.

     

    1. Windows·Linux x64: JIT/AOT 최소 x86-64-v2, ReadyToRun 타깃 x86-64-v3
    2. Windows Arm64: JIT/AOT 최소 armv8.0-a + LSE, ReadyToRun 타깃 armv8.2-a + RCPC
    3. Linux Arm64: JIT/AOT 최소는 그대로 armv8.0-a, ReadyToRun 타깃만 armv8.0-a + LSE로 변경
    4. Apple: 변경 없음

     

    요구사항을 만족하지 않는 장비에서는 앱이 시작 단계에서 종료되며 다음 메시지가 출력됩니다.

     

    The current CPU is missing one or more of the baseline instruction sets.

     

    구형 온프레미스 VM, 임베디드 보드, 오래된 클라우드 인스턴스 타입을 쓰는 조직은 배포 전에 실제 플래그를 확인합니다.

     

    # Linux
    grep -o -m1 -E 'sse4_2|popcnt|cx16' /proc/cpuinfo | sort -u
    
    # Windows (PowerShell)
    Get-CimInstance Win32_Processor | Select-Object Name, Caption

     

    R2R 타깃이 v3로 올라간 만큼, 하드웨어가 v2만 만족하는 환경에서는 시작 시 JIT 부담이 늘어납니다. 콜드 스타트 시간이 중요한 서비스는 스테이징에서 시작 시간을 다시 측정해야 합니다.

     

    3. C# 15 언어 변경점

     

    net11.0 프로젝트는 별도 설정 없이 C# 15를 사용합니다. 실무 영향이 큰 두 가지는 union 타입과 closed 계층입니다.

     

    union은 여러 case 타입 중 하나를 표현하는 값 타입입니다. 반환 타입으로 결과와 실패를 함께 돌려줄 때 object나 무관한 기반 클래스 없이 표현할 수 있습니다.

     

    public sealed record Product(int Id, string Name);
    public sealed record ProductNotFound(int Id);
    
    public union ProductLookup(Product, ProductNotFound);
    
    ProductLookup result = new ProductNotFound(42);
    
    string message = result switch
    {
        Product p => $"Found {p.Name}",
        ProductNotFound m => $"No product with ID {m.Id}",
    };
    
    Console.WriteLine(message);

     

    case 타입을 모두 처리하지 않으면 switch 식이 컴파일되지 않습니다. 예외로 흘리던 분기가 컴파일 타임 검사로 옮겨오는 것이 핵심입니다.

     

    closed 계층은 파생을 선언 어셈블리 안으로 제한합니다. 상속 관계를 직접 소유한 모델이라면 union보다 이쪽이 맞습니다.

     

    public closed record class GateState;
    public record class Closed : GateState;
    public record class Open(float Percent) : GateState;
    
    string Describe(GateState state) => state switch
    {
        Closed => "closed",
        Open(var percent) => $"{percent}% open",
    };

     

    closed 클래스는 암묵적으로 abstract이며 sealed, static, abstract 한정자와 함께 쓸 수 없습니다. 파생은 전이되지 않으므로, 하위까지 검사를 확장하려면 중간 타입도 closed로 선언합니다.

     

    일상 코드에 바로 쓰는 기능도 추가됐습니다. collection expression에 생성자 인자를 넘기는 with(...) 요소, extension indexer, label을 지정하는 break/continue입니다.

     

    HashSet<string> names = [with(StringComparer.OrdinalIgnoreCase), "Alice", "ALICE", "Bob"];
    Console.WriteLine(names.Count);   // 2
    
    outer: for (int row = 0; row < grid.Height; row++)
    {
        for (int column = 0; column < grid.Width; column++)
        {
            if (grid[row, column].IsBlocked) continue outer;
            if (grid[row, column].IsGoal) break outer;
        }
    }

     

    메모리 안전성 재정의는 preview 상태이므로 운영 코드에 적용하지 않습니다.

     

    4. SDK·툴링 변경점

     

    빌드 환경과 CI 파이프라인에 영향을 주는 항목입니다.

     

    1. Native AOT CLI 호스트가 기본 활성화됩니다. help, version 같은 명령이 관리형 CLI를 띄우지 않고 실행되며, 관리형 실행이 필요한 명령만 기존 경로를 씁니다.
    2. MSBuild 서버가 CLI 호출 사이에 기본으로 상주합니다. 짧은 명령을 연속 실행하는 CI에서 이득이 크고, 메모리 사용량은 늘어납니다.
    3. 컨테이너 발행에 SOURCE_DATE_EPOCH 기반 재현 가능한 이미지 다이제스트가 추가됐습니다.
    4. 대상 매니페스트가 이미 있으면 중복 레이어 업로드를 건너뜁니다.
    5. NuGet 소스 설정에 최소 패키지 공개 경과 시간(minimum package publication age) 옵션이 생겼습니다. 갓 올라온 버전을 일정 기간 선택 대상에서 제외하는 정책 제어이며, 취약점 검사를 대체하지 않습니다.
    6. 파일 기반 앱이 #:include로 여러 소스 파일로 확장됩니다.
    7. dotnet watch에 Aspire 앱 호스트 통합, 크래시 복구, 모바일 기기 선택이 추가됐습니다.

     

    Native AOT CLI 호스트와 MSBuild 서버 상주는 기본값 변경이므로, 컨테이너 이미지에 dotnet CLI를 넣어 쓰는 파이프라인은 동작 확인이 필요합니다.

     

    5. ASP.NET Core·EF Core 11 변경점

     

    웹 API 실무에서 코드 수정이 발생하는 항목입니다.

     

    1. OpenAPI 3.2가 기본이 됩니다. 3.0 문서를 소비하는 클라이언트 생성기나 게이트웨이는 스키마 버전을 고정해야 합니다.
    2. Minimal API에 비동기 유효성 검사가 추가됐습니다. 검증기를 async로 구현한 경우 옵션에 대한 동기 접근이 예외가 되는 변경이 함께 있습니다.
    3. SignalR 인증 갱신을 지원합니다. 장기 연결에서 토큰 만료 후 재연결 없이 인증을 갱신할 수 있습니다.
    4. Blazor는 탭 비활성 시 회로 자동 일시정지, 정적 SSR 하위 트리 출력 캐시가 추가됐습니다.
    5. Agent UI용 실험적 Blazor AI 컴포넌트와 AG-UI 연동이 포함됩니다. 실험 단계이므로 운영 적용 대상이 아닙니다.
    6. EF Core 11은 벡터 검색과 벡터 인덱스를 지원합니다.
    7. 라이브러리에는 Zstandard 압축이 기본 포함되고, Process API 확장, System.Text.Json 개선, 복사 없는 인메모리 스트림 어댑터, LINQ Join 개선이 들어갔습니다.

     

    전역 예외 처리와 DI 관련 동작 변경도 확인 대상입니다. IHost.RunAsync와 IHost.StopAsync가 BackgroundService 실패 시 예외를 던지고, DI 스코프 Dispose 예외가 집계되며, 연결된 구성에서 빈 문자열이 앞선 공급자를 덮어씁니다. 서비스 시작 실패를 조용히 삼키던 코드는 이 변경으로 프로세스가 종료될 수 있습니다.

     

    6. 마이그레이션 실행 순서

     

    1. 대상 프로젝트의 현재 TFM과 패키지 버전을 기록합니다.
    2. .NET 11 SDK를 설치하고 global.json으로 버전을 고정합니다.
    3. TFM을 net11.0으로 올리고 빌드합니다.
    4. Microsoft.Extensions.*, ASP.NET Core, EF Core 패키지를 11.x로 정렬합니다.
    5. breaking change 목록과 최소 하드웨어 요구사항을 대조합니다.
    6. 컨테이너 베이스 이미지 태그와 CI 런타임을 11.0으로 맞춥니다.
    7. 스테이징에서 시작 시간·메모리·처리량을 측정한 뒤 배포합니다.

     

    # 2. SDK 고정 (저장소 루트)
    dotnet new globaljson --sdk-version 11.0.100 --roll-forward latestFeature

     

    {
      "sdk": {
        "version": "11.0.100",
        "rollForward": "latestFeature"
      }
    }

     

    <!-- 3. TFM 변경 -->
    <PropertyGroup>
      <TargetFramework>net11.0</TargetFramework>
      <LangVersion>15.0</LangVersion>
      <Nullable>enable</Nullable>
    </PropertyGroup>

     

    # 3~4. 빌드 및 패키지 정렬 확인
    dotnet restore
    dotnet build -c Release
    dotnet list package --outdated

     

    # 6. 컨테이너 런타임 태그 확인
    docker pull mcr.microsoft.com/dotnet/aspnet:11.0
    docker pull mcr.microsoft.com/dotnet/sdk:11.0

     

    패키지 정렬에서 자주 남는 항목은 Microsoft.Extensions.* 입니다. .NET 11부터 일부 Microsoft.Extensions 패키지가 공유 프레임워크에 포함되므로, 같은 어셈블리를 패키지로도 참조하면 버전 충돌이 납니다. 공유 프레임워크에 포함된 패키지는 PackageReference에서 제거합니다.

     

    7. 배포 후 롤백 기준

     

    1. 롤백은 런타임 롤백이 아니라 이미지·배포 슬롯 단위로 준비합니다. .NET 11 앱을 .NET 10 런타임 위에서 실행할 수는 없습니다.
    2. 시작 시간이 기존 대비 유의미하게 늘면 R2R 타깃과 하드웨어 조합을 먼저 확인합니다.
    3. Native AOT CLI 호스트·MSBuild 서버 상주로 CI 메모리가 상승하면 환경 변수로 개별 비활성화합니다.
    4. OpenAPI 3.2 전환으로 클라이언트 생성이 깨지면 문서 버전을 3.0으로 고정하고 별도 작업으로 분리합니다.

     

    정리

     

    .NET 11은 STS 2년 지원 릴리즈이고, 실무에서 먼저 부딪히는 것은 언어 기능이 아니라 최소 하드웨어 요구사항과 SDK 기본값 변경입니다. 마이그레이션은 global.json과 TFM 고정, 패키지 정렬, 컨테이너 태그 교체, 스테이징 측정 순서로 진행하고, 롤백은 이미지 단위로 준비해 두면 됩니다.

Posted by virtualgiraffe.