복잡한 리액트(React) 상태 관리, 비대해진 node_modules, 그리고 끝없는 JSON 직렬화/역직렬화에 지치셨나요? 백엔드 개발자에게 가장 편안한 언어인 Go를 사용하면서도, 현대적인 SPA(Single Page Application) 같은 사용자 경험을 제공하는 GOTH 스택을 소개합니다. GOTH(Go + Templ + HTMX) 스택은 최근 Go 커뮤니티에서 “다시 재미있게 웹 개발을 하자(Make Web Dev Fun Again)” 는 흐름과 함께 큰 주목을 받고 있습니다. 복잡한 JS 프레임워크 없이 Go의 강점인 단순함과 성능을 그대로 살릴 수 있는 것이 특징입니다.

이 글은 요청에 대한 Gemini 3 Pro 의 답변입니다.


GOTH 스택이란?#

  • Go: 강력하고 단순한 백엔드 서버 (Go 1.22+ net/http 사용)
  • Templ: Go 언어로 작성하는 타입 안전(Type-safe) 한 HTML 템플릿 언어
  • HTMX: JavaScript 작성 없이 HTML 속성만으로 AJAX 요청과 DOM 갱신을 처리하는 라이브러리

이 셋의 조합은 “HTML을 서버에서 만들어(Templ), 와이어로 전송하고(Go), 클라이언트가 갈아 끼운다(HTMX)” 는 아주 단순한 철학으로 돌아갑니다.


1. 프로젝트 부트스트랩 (Bootstrap)#

가장 먼저 프로젝트 폴더를 만들고 Go 모듈을 초기화합니다. 그리고 핵심 도구인 templ을 설치합니다.

# 1. 프로젝트 폴더 생성 및 이동
mkdir goth-todo
cd goth-todo

# 2. Go 모듈 초기화
go mod init goth-todo

# 3. Templ CLI 도구 설치 (아직 없다면)
go install github.com/a-h/templ/cmd/templ@latest

# 4. 프로젝트에 Templ 라이브러리 추가
go get github.com/a-h/templ

폴더 구조는 아주 심플하게 가져갑니다.

goth-todo/
├── go.mod
├── go.sum
├── main.go      (서버 및 로직)
└── view.templ   (UI 컴포넌트)

2. UI 만들기: view.templ#

Templ은 HTML을 Go 코드처럼 작성하게 해줍니다. view.templ 파일을 만들고 아래 코드를 작성합니다. 여기서 우리는 두 가지 컴포넌트를 정의합니다.

  1. Page: 전체 HTML 뼈대
  2. TodoItem: 할 일 아이템 하나 (리스트에 추가될 조각)
package main

// view.templ

// 전체 페이지 레이아웃
templ Page() {
	<!DOCTYPE html>
	<html>
	<head>
		<title>GOTH Todo</title>
		<script src="https://unpkg.com/htmx.org@1.9.10"></script>
		<style>
			body { font-family: sans-serif; padding: 20px; }
			.todo { margin: 5px 0; padding: 5px; border-bottom: 1px solid #eee; }
		</style>
	</head>
	<body>
		<h1>GOTH Todo List </h1>

		<form hx-post="/add" hx-target="#todo-list" hx-swap="beforeend" hx-on::after-request="this.reset()">
			<input type="text" name="content" placeholder="할 일을 입력하세요..." required />
			<button type="submit">추가</button>
		</form>

		<div id="todo-list">
			</div>
	</body>
	</html>
}

// 할 일 아이템 하나 (서버가 응답할 HTML 조각)
templ TodoItem(content string) {
	<div class="todo">
		{ content }
	</div>
}

💡 포인트: HTML 속성(hx-...) 몇 개만으로 “폼을 제출하면, 서버에 데이터를 보내고, 돌아온 HTML 조각을 리스트 끝에 붙인다"는 로직이 완성되었습니다.

이제 터미널에서 templ 명령어로 이 파일을 Go 코드로 변환합니다.

templ generate

이 명령을 실행하면 view_templ.go 파일이 자동으로 생성됩니다. (이 파일은 직접 수정하지 않습니다.)


3. 서버 구현하기: main.go#

이제 Go 서버를 만듭니다. Go 1.22부터 강력해진 표준 라이브러리 net/http를 사용합니다.

package main

import (
	"net/http"
	
	"github.com/a-h/templ"
)

func main() {
	// 1. 메인 페이지 핸들러 (GET /)
	http.Handle("GET /", templ.Handler(Page()))

	// 2. 할 일 추가 핸들러 (POST /add)
	http.HandleFunc("POST /add", func(w http.ResponseWriter, r *http.Request) {
		// 폼 데이터 파싱
		content := r.FormValue("content")

		// DB에 저장하는 로직이 들어갈 자리 (여기선 생략)
		
		// 핵심: 전체 페이지가 아니라 "새로 추가된 아이템 HTML 조각"만 응답함
		component := TodoItem(content)
		component.Render(r.Context(), w)
	})

	// 서버 시작
	println("Listening on http://localhost:8080")
	http.ListenAndServe(":8080", nil)
}

💡 포인트:

  • templ.Handler(Page()): Templ 컴포넌트는 그 자체로 http.Handler가 될 수 있습니다.
  • POST /add: JSON을 리턴하지 않습니다. TodoItem이라는 HTML 조각(Fragment) 을 렌더링해서 클라이언트로 보냅니다. HTMX는 이 조각을 받아서 DOM에 끼워 넣습니다.

4. 실행 및 결과 확인#

이제 모든 준비가 끝났습니다.

go run .

브라우저에서 http://localhost:8080을 열어보세요. 입력창에 할 일을 적고 엔터를 치면, 페이지 새로고침 없이 리스트에 아이템이 착착 추가되는 것을 볼 수 있습니다.

개발자 도구(F12)의 Network 탭을 확인해보세요.

  1. /add로 Form Data를 보냅니다.
  2. 서버는 <div class="todo">할일</div> 라는 HTML 문자열만 응답합니다.
  3. 브라우저는 이 HTML을 받아 화면에 그립니다.

왜 GOTH 스택인가?#

  1. 단순함 (Simplicity): 프론트엔드 빌드 파이프라인(Webpack, Vite 등)이 필요 없습니다. Go 바이너리 하나면 배포 끝입니다.
  2. 타입 안전성 (Type Safety): view.templ에서 오타를 내거나 잘못된 타입을 사용하면 Go 컴파일러가 빌드 시점에 잡아냅니다. “런타임 에러"와 작별하세요.
  3. 생산성 (Productivity): 백엔드 개발자가 컨텍스트 스위칭 없이(Go만 생각하며) 풀스택 기능을 구현할 수 있습니다.

마치며#

이 예제는 시작일 뿐입니다. hx-delete로 삭제 기능을, hx-trigger로 실시간 업데이트를 구현해보세요. 복잡한 로직은 Go가 다 처리하고, 브라우저는 그저 보여주기만 하면 됩니다.

Go의 단순함과 현대적인 웹의 편리함을 동시에 잡고 싶다면, 지금 바로 GOTH 해보세요! 🦇