@@ -225,7 +225,8 @@ async function run(): Promise<void> {
225225 * If the user does not provide the necessary flags, prompt them for their
226226 * preferences, unless `--yes` option was specified, or when running in CI.
227227 */
228- const skipPrompt = ciInfo . isCI || opts . yes
228+ let skipPrompt = ciInfo . isCI || opts . yes
229+ let useRecommendedDefaults = false
229230
230231 if ( ! example ) {
231232 const defaults : typeof preferences = {
@@ -242,8 +243,127 @@ async function run(): Promise<void> {
242243 disableGit : false ,
243244 reactCompiler : false ,
244245 }
245- const getPrefOrDefault = ( field : string ) =>
246- preferences [ field ] ?? defaults [ field ]
246+
247+ type DisplayConfigItem = {
248+ key : keyof typeof defaults
249+ // Map setting values to display labels
250+ // For boolean: { true: 'Label', false: 'Other Label' } or just { true: 'Label' }
251+ // For string: { 'value1': 'Label 1', 'value2': 'Label 2' }
252+ values ? : Record < string | number | symbol , string>
253+ }
254+
255+ const displayConfig : DisplayConfigItem [ ] = [
256+ {
257+ key : 'typescript' ,
258+ values : { true : 'TypeScript' , false : 'JavaScript' } ,
259+ } ,
260+ { key : 'linter' , values : { eslint : 'ESLint' , biome : 'Biome' } } ,
261+ { key : 'reactCompiler' , values : { true : 'React Compiler' } } ,
262+ { key : 'tailwind' , values : { true : 'Tailwind CSS' } } ,
263+ { key : 'srcDir' , values : { true : 'src/' } } ,
264+ { key : 'app' , values : { true : 'App Router' , false : 'Pages Router' } } ,
265+ { key : 'turbopack' , values : { true : 'Turbopack' } } ,
266+ ]
267+
268+ // Helper to format settings for display based on displayConfig
269+ const formatSettingsDescription = (
270+ settings : Record < string , boolean | string >
271+ ) => {
272+ const descriptions : string [ ] = [ ]
273+
274+ for ( const config of displayConfig ) {
275+ const value = settings [ config . key ]
276+
277+ if ( config . values ) {
278+ // Look up the display label for this value
279+ const label = config . values [ String ( value ) ]
280+ if ( label ) {
281+ descriptions . push ( label )
282+ }
283+ }
284+ }
285+
286+ return descriptions . join ( ', ' )
287+ }
288+
289+ // Check if we have saved preferences
290+ const hasSavedPreferences = Object . keys ( preferences ) . length > 0
291+
292+ // Check if user provided ANY flags at all
293+ // If they did, skip the "recommended defaults" prompt and go straight to
294+ // individual prompts for any missing options
295+ const hasProvidedOptions = args . some ( ( arg ) => arg . startsWith ( '--' ) )
296+
297+ // Only show the "recommended defaults" prompt if:
298+ // - Not in CI and not using --yes flag
299+ // - User hasn't provided any custom options
300+ if ( ! skipPrompt && ! hasProvidedOptions ) {
301+ const choices : Array < {
302+ title : string
303+ value : string
304+ description ?: string
305+ } > = [
306+ {
307+ title : 'Yes, use recommended defaults' ,
308+ value : 'recommended' ,
309+ description : formatSettingsDescription ( defaults ) ,
310+ } ,
311+ {
312+ title : 'No, customize settings' ,
313+ value : 'customize' ,
314+ description : 'Choose your own preferences' ,
315+ } ,
316+ ]
317+
318+ // Add "reuse previous settings" option if we have saved preferences
319+ if ( hasSavedPreferences ) {
320+ const prefDescription = formatSettingsDescription ( preferences )
321+ choices . splice ( 1 , 0 , {
322+ title : 'No, reuse previous settings' ,
323+ value : 'reuse' ,
324+ description : prefDescription ,
325+ } )
326+ }
327+
328+ const { setupChoice } = await prompts (
329+ {
330+ type : 'select' ,
331+ name : 'setupChoice' ,
332+ message : 'Would you like to use the recommended Next.js defaults?' ,
333+ choices,
334+ initial : 0 ,
335+ } ,
336+ {
337+ onCancel : ( ) => {
338+ console . error ( 'Exiting.' )
339+ process . exit ( 1 )
340+ } ,
341+ }
342+ )
343+
344+ if ( setupChoice === 'recommended' ) {
345+ useRecommendedDefaults = true
346+ skipPrompt = true
347+ } else if ( setupChoice === 'reuse' ) {
348+ skipPrompt = true
349+ }
350+ }
351+
352+ // If using recommended defaults, populate preferences with defaults
353+ // This ensures they are saved for reuse next time
354+ if ( useRecommendedDefaults ) {
355+ Object . assign ( preferences , defaults )
356+ }
357+
358+ const getPrefOrDefault = ( field : string ) => {
359+ // If using recommended defaults, always use hardcoded defaults
360+ if ( useRecommendedDefaults ) {
361+ return defaults [ field ]
362+ }
363+
364+ // If not using the recommended template, we prefer saved preferences, otherwise defaults.
365+ return preferences [ field ] ?? defaults [ field ]
366+ }
247367
248368 if ( ! opts . typescript && ! opts . javascript ) {
249369 if ( skipPrompt ) {
0 commit comments