Different behaivor between buildSrc and include build build-logic

I thought there are no difference between buildSrc and include-bulid, but there is.

In buildSrc, if put a plugin as implementation, it will be exposed in other projects.

But in include-build, no matter what you do as implementation or api, the plugin is not exposed.

To summarize briefly

In buildSrc

plugins {
  `kotlin-dsl`
}

repositories {
  gradlePluginPortal()
}

dependencies {
  implementation("some-plugin:1.2.3")
}

definition allows other modules can use like below

plugin {
  id("some-plugin")
}

But with include-build

When I do the above, I get an error saying that the plugin is not found.

Is this intended behaivor in include-build?

I thought there are no difference between buildSrc and include-bulid, but there is.

Well, that assumption was wrong.
buildSrc is always special.
Since Gradle 8, it was made even more similar to an included build, but there are still slight differences between the two.

Is this intended behaivor in include-build?

Yes.

buildSrc is a project that is built always before the main build and put to the classpath of all build scripts by being in a parent class loader of the class loader for the build scripts.
This way all dependencies you declare there are available everywhere, but on the other hand it also overrides everything added in a build script classpath as there is no conflict resolution and so on.
And any change in buildSrc invalidates all projects and tasks.

With an included build, things are only built and used if you actually use them and only where you use them and also with conflict resolution just like normal binary plugins you depend on.
If in the included build a plugin is built that you use in a buildscript, then this plugin is actually built and also added to the build script classpath, including its dependencies.
But if you don’t use a plugin from the included build, nothing is built and nothing is added, as that would needlessly invalidate tasks like buildSrc is doing and that would be bad.

Thanks for explanation. But I have one more question.

I think I am still mis-understand about composite build. :frowning:

the sample repository is here

to demonstration purpose, I restricted main project to resolve plugin from mavenLocal only

 pluginManagement { 
    repositories {
         mavenLocal()
     } 
}  

includeBuild("build-logic")
 include("application") 

and inside “build-logic” I decleared repository as gradlePluginPortal() and add some plugins

here is my build.grdle.kts in “build-logic”

plugins {
     `kotlin-dsl` 
}
  repositories { 
    gradlePluginPortal() 
}
  dependencies { 
    implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.22")    
    implementation("org.jetbrains.kotlin:kotlin-allopen:1.9.22") 
} 

and I declear convention plugin like below

plugins { 
    kotlin("jvm")
 }  
repositories { 
    mavenCentral()
 } 

after that I create “application” subproject and try to use convention plugin

plugins {
     id("me.jmlab.gradle.kotlin-common-conventions") 
} 

but this case also configuration failed because plugin not found in application subproject.

I asummed that classpath of build-logic exposed to “application”. but It is not.

If I disabled “application” subproject than “build-logic” can build successfully.

The build-logic is an own build the result of which is consumed.
Repository declarations of other builds do not leak into the build that include them.
Each build has to define the repositories where the plugins and dependencies can be resolved from.
So if your plugin needs dependencies that are found on gradlePluginPortal(), you also have to define that on the consuming build as plugin repository.